AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 60342
Accepted
Jack Douglas
Jack Douglas
Asked: 2014-03-07 10:49:14 +0800 CST2014-03-07 10:49:14 +0800 CST 2014-03-07 10:49:14 +0800 CST

IS DISTINCT FROM 可以与 ANY 或 ALL 以某种方式结合吗?

  • 772

是一种 postgres 组合方式IS DISTINCT FROM还是ANY其他一些巧妙的方式来获得相同的结果?

select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo <> any(array[null, 'A']);

 count
-------
     1
(1 row)

select count(*)
from (select 'A' foo union all select 'Z' union all select null) z
where foo is distinct from any(array[null, 'A']);  

ERROR:  syntax error at or near "any"
LINE 3: where foo is distinct from any(array[null, 'A']);
                                   ^
postgresql null
  • 3 3 个回答
  • 2131 Views

3 个回答

  • Voted
  1. Daniel Vérité
    2014-03-07T14:30:00+08:002014-03-07T14:30:00+08:00

    将其视为语法问题,ANY定义为(在Row and Array Comparisons中):

    表达式运算符 ANY(数组表达式)

    但is distinct from它不是运算符,它是一个“构造”,正如我们在比较运算符中所说的那样:

    当这种行为不合适时,使用 IS [ NOT ] DISTINCT FROM 结构

    由于 PostgreSQL 有用户定义的运算符,我们可以为此目的定义一个运算符/函数组合:

    create function is_distinct_from(text, text) returns bool as 
    'select $1 is distinct from $2;' language sql;
    
    create operator <!> (
     procedure=is_distinct_from(text,text),
     leftarg=text, rightarg=text
    );
    

    然后它可以先于ANY:

    select count(*)
    from (select 'A' foo union all select 'Z' union all select null) z
    where foo <!> any(array[null, 'A']);  
    
    数数
    --------
         3
    (1 行)
    
    • 15
  2. Erwin Brandstetter
    2014-03-07T21:39:53+08:002014-03-07T21:39:53+08:00

    操作员

    这是建立在@Daniel 聪明的 operator之上的。
    在此过程中,使用多态类型创建函数/运算符组合。然后它适用于任何类型 - 就像构造一样。
    并制作函数IMMUTABLE。

    CREATE FUNCTION is_distinct_from(anyelement, anyelement)
      RETURNS bool LANGUAGE sql IMMUTABLE AS 
    'SELECT $1 IS DISTINCT FROM $2';
    
    CREATE OPERATOR <!> (
      PROCEDURE = is_distinct_from(anyelement,anyelement),
      LEFTARG  = anyelement
    , RIGHTARG = anyelement
    );

    使用 symbolhound 进行的快速搜索是空的,因此该运算符<!>似乎没有在任何模块中使用。

    如果您打算大量使用此运算符,您可能会进一步充实它以帮助查询规划器(如评论中建议的 losthorse)。对于初学者,您可以添加COMMUTATORandNEGATOR子句来辅助查询优化器。CREATE OPERATOR从上面替换为:

    CREATE OPERATOR <!> (
      PROCEDURE = is_distinct_from(anyelement,anyelement),
      LEFTARG  = anyelement
    , RIGHTARG = anyelement
    , COMMUTATOR = <!>
    , NEGATOR = =!=
    );
    

    并添加:

    CREATE FUNCTION is_not_distinct_from(anyelement, anyelement)
      RETURNS bool LANGUAGE sql IMMUTABLE AS 
    'SELECT $1 IS NOT DISTINCT FROM $2';
    
    CREATE OPERATOR =!= (
      PROCEDURE = is_not_distinct_from(anyelement,anyelement),
      LEFTARG  = anyelement
    , RIGHTARG = anyelement
    , COMMUTATOR = =!=
    , NEGATOR = <!>
    );
    

    但是附加子句对手头的用例没有帮助,并且仍然不会使用普通索引。实现这一点要复杂得多。(我没试过。)详情请阅读手册中的“运营商优化信息”一章。

    测试用例

    只有当数组中的所有值都相同时,问题中的测试用例才能成功。对于问题 ( '{null,A}'::text[]) 中的数组,结果始终为 TRUE。这是故意的吗?我为“IS DISTINCT FROM ALL”添加了另一个测试:

    SELECT foo
         , foo <!> ANY ('{null,A}'::text[]) AS chk_any
         , foo <!> ALL ('{null,A}'::text[]) AS chk_all
    FROM (
       VALUES ('A'),('Z'),(NULL)
       ) z(foo)
    
     foo | chk_any | chk_all
    -----+---------+---------
     A   | t       | f
     Z   | t       | t
         | t       | f
    

    标准运算符的替代方案

    foo IS DISTINCT FROM ANY (test_arr) -- illegal syntax
    

    几乎可以翻译成

    foo = ALL (test_arr) IS NOT TRUE

    foo = ALL (test_arr)产量...

    TRUE .. 如果所有元素都是foo
    FALSE.. 如果任何NOT NULL元素是<> foo
    NULL .. 如果至少一个元素IS NULL并且没有元素是<> foo

    所以,剩下的极端情况是
    - foo IS NULL
    - 并且 test_arr只包含NULL元素。

    如果可以排除其中任何一个,我们就完成了。因此,使用简单的测试 if
    - 列已定义NOT NULL。
    -或者你知道数组永远不会都是 NULL。

    否则,额外测试:

    AND ('A' = ALL(test_arr) IS NOT NULL OR 
         'B' = ALL(test_arr) IS NOT NULL OR
         foo IS NOT NULL)
    

    Where'A'和'B'可以是任何不同的值。在这个相关问题下的解释和替代方案:
    Is array all NULLs in PostgreSQL

    同样,如果您知道任何不能存在于 中的值,test_arr例如空字符串'',您仍然可以简化:

    AND ('' = ALL(test_arr) IS NOT NULL OR
         foo IS NOT NULL)
    

    这是检查所有组合的完整测试矩阵:

    SELECT foo, test_arr
         , foo = ALL(test_arr) IS NOT TRUE  AS test_simple
         , foo = ALL(test_arr) IS NOT TRUE
           AND ('A' = ALL(test_arr) IS NOT NULL OR
                'B' = ALL(test_arr) IS NOT NULL OR 
                foo IS NOT NULL)            AS test_sure 
    FROM (
       VALUES ('A'),('Z'),(NULL)
       ) v(foo)
    CROSS JOIN (
       VALUES ('{null,A}'::text[]),('{A,A}'),('{null,null}')
       ) t(test_arr)
    
     foo |  test_arr   | test_simple | test_sure
    -----+-------------+-------------+-----------
     A   | {NULL,A}    | t           | t
     A   | {A,A}       | f           | f   -- only TRUE case
     A   | {NULL,NULL} | t           | t
     Z   | {NULL,A}    | t           | t
     Z   | {A,A}       | t           | t
     Z   | {NULL,NULL} | t           | t
         | {NULL,A}    | t           | t
         | {A,A}       | t           | t
         | {NULL,NULL} | t           | f   -- special case
    

    这比Andriy 的EXCEPT解决方案要冗长一些,但速度要快得多。

    • 13
  3. Best Answer
    Andriy M
    2014-03-07T11:27:15+08:002014-03-07T11:27:15+08:00

    也许像这样:

    select foo
         , exists (values (null), ('A') except select foo) chk_any
         , not exists (values (null), ('A') intersect select foo) chk_all
    from ( values ('A'),('Z'),(null) ) z(foo);
    
     foo | chk_any | chk_all
    -----+---------+---------
     A   | t       | f
     Z   | t       | t
         | t       | f
    

    请注意,不仅null在“数组”中,而且在null以z这种方式比较。

    • 8

相关问题

  • 存储过程可以防止 SQL 注入吗?

  • PostgreSQL 中 UniProt 的生物序列

  • 默认为 NULL 还是 NOT NULL?

  • 何时使用 NULL 以及何时使用空字符串?

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve