这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

搜索条件中使用的子查询

子查询需要用作搜索条件才能过滤结果。它们指定了从包含查询的 select-list、查询表达式或子查询自身返回行的条件。此操作评估为 TRUE、FALSE 或 UNKNOWN (NULL)。

语法

search‑condition {
    [ { AND | OR | NOT } {  predicate | ( search‑condition ) } ]
   }[,... ]
 predicate
     { expression comparison‑operator expression
         | string‑expression [ NOT ] { LIKE | ILIKE | LIKEB | ILIKEB } string-expression
         | expression IS [ NOT ] NULL
         | expression [ NOT ] IN ( subquery | expression[,... ] )
         | expression comparison‑operator [ ANY | SOME ] ( subquery )
         | expression comparison‑operator ALL ( subquery )
         | expression OR ( subquery )
         | [ NOT ] EXISTS ( subquery )
         | [ NOT ] IN ( subquery )
     }

参数

1 - 逻辑运算符 AND 和 OR

AND 和 OR 逻辑运算符会组合两个条件。当由 AND 关键字联接的两个条件都有匹配时,AND 评估为 TRUE,当由 OR 关键字联接的一个条件有匹配时,则 OR 评估为 TRUE。

OR 子查询(复杂表达式)

Vertica 支持使用 OR 的更复杂的表达式中的子查询,例如:

  • 连接表达式中有一个以上子查询:

    (SELECT MAX(b) FROM t1) + SELECT (MAX FROM t2) a IN (SELECT a FROM t1) OR b IN (SELECT x FROM t2)
    
  • 连接表达式中的 OR 子句至少包含一个子查询:

    a IN (SELECT a FROM t1) OR b IN (SELECT x FROM t2) a IN (SELECT a from t1) OR b = 5
    a = (SELECT MAX FROM t2) OR b = 5
    
  • 只有一个子查询,而且它包含在另一个表达式中:

    x IN (SELECT a FROM t1) = (x = (SELECT MAX FROM t2) (x IN (SELECT a FROM t1) IS NULL
    

如何评估 AND 查询

Vertica 会分别对待 AND(连接)运算符分隔的表达式。例如,如果 WHERE 子句为:

  WHERE (a IN (SELECT a FROM t1) OR b IN (SELECT x FROM t2)) AND (c IN (SELECT a FROM t1))

则将查询解释为两个连接表达式:

  1. (a IN (SELECT a FROM t1) OR b IN (SELECT x FROM t2))

  2. (c IN (SELECT a FROM t1))

第一个表达式会被认为是一个复杂的子查询,而第二个表达式则不会。

示例

以下列表显示了过滤 WHERE 子句中复杂条件的几种方法:

  • 子查询和非子查询条件之间的 OR 表达式:

    => SELECT x FROM t WHERE x > (SELECT SUM(DISTINCT x) FROM t GROUP BY y) OR x < 9;
    
  • 两个子查询之间的 OR 表达式:

    => SELECT * FROM t WHERE x=(SELECT x FROM t) OR EXISTS(SELECT x FROM tt);
    
  • 子查询表达式:

    => SELECT * FROM t WHERE x=(SELECT x FROM t)+1 OR x<>(SELECT x FROM t)+1;
    
  • 包含 [NOT] IN 子查询的 OR 表达式:

    => SELECT * FROM t WHERE NOT (EXISTS (SELECT x FROM t)) OR x >9;
    
  • 包含 IS [NOT] NULL 子查询的 OR 表达式:

    => SELECT * FROM t WHERE (SELECT * FROM t)IS NULL OR (SELECT * FROM tt)IS NULL;
    
  • 包含 boolean 列和返回 Boolean 数据类型的子查询的 OR 表达式:

    => SELECT * FROM t2 WHERE x = (SELECT x FROM t2) OR x;
    
  • CASE 语句中的 OR 表达式:

    => SELECT * FROM t WHERE CASE WHEN x=1 THEN x > (SELECT * FROM t)
           OR x < (SELECT * FROM t2) END ;
    
  • 分析函数、NULL 处理函数、字符串函数、数学函数等等:

    => SELECT x FROM t WHERE x > (SELECT COALESCE (x,y) FROM t GROUP BY x,y) OR
           x < 9;
    
  • 在用户定义的函数(假设 f() 为 1)中:

    => SELECT * FROM t WHERE x > 5 OR x = (SELECT f(x) FROM t);
    
  • 在不同的位置使用圆括号重建查询:

    => SELECT x FROM t WHERE (x = (SELECT x FROM t) AND y = (SELECT y FROM t))
           OR (SELECT x FROM t) =1;
    
  • 多列子查询:

    => SELECT * FROM t WHERE (x,y) = (SELECT x,y FROM t) OR x > 5;
    
  • 子查询左侧的常数/NULL:

    => SELECT * FROM t WHERE x > 5 OR 5 = (SELECT x FROM t);
    

另请参阅

2 - 替代表达式

返回单值(与 IN 子查询返回的值列表不同)的子查询可用于在 SQL 中允许使用表达式的任何位置。它可以是列名称、常数、函数、标量子查询或由运算符或子查询连接的列名称、常数和函数的组合。

例如:

=> SELECT c1 FROM t1 WHERE c1 = ANY (SELECT c1 FROM t2) ORDER BY c1;
=> SELECT c1 FROM t1 WHERE COALESCE((t1.c1 > ANY (SELECT c1 FROM t2)), TRUE);
=> SELECT c1 FROM t1 GROUP BY c1 HAVING
     COALESCE((t1.c1 <> ALL (SELECT c1 FROM t2)), TRUE);

多列表达式也受支持:

=> SELECT c1 FROM t1 WHERE (t1.c1, t1.c2) = ALL (SELECT c1, c2 FROM t2);
=> SELECT c1 FROM t1 WHERE (t1.c1, t1.c2) <> ANY (SELECT c1, c2 FROM t2);

如果用作表达式的任何子查询返回了一个以上的行,则 Vertica 将返回查询错误:

=> SELECT c1 FROM t1 WHERE c1 = (SELECT c1 FROM t2) ORDER BY c1;
   ERROR:  more than one row returned by a subquery used as an expression

另请参阅

3 - 比较运算符

Vertica 支持包含以下任何运算符的 WHERE 子句中的 Boolean 子查询表达式:

> < >= <= = <> <=>

WHERE 子句子查询会筛选结果,并采用以下格式:

SELECT <column, ...> FROM <table>
WHERE <condition> (SELECT <column, ...> FROM <table> WHERE <condition>);

只要比较有意义,这些条件可适用于所有数据类型。所有比较运算符均为二元运算符,可返回 TRUE、FALSE 或 UNKNOWN (NULL) 这些值。

表达式可以仅与外查询块中的一个外表相关,而且这些相关表达式可以是比较运算符。

支持以下子查询场景:

SELECT * FROM T1 WHERE T1.x =  (SELECT MAX(c1) FROM T2);
SELECT * FROM T1 WHERE T1.x >= (SELECT MAX(c1) FROM T2 WHERE T1.y = T2.c2);
SELECT * FROM T1 WHERE T1.x <= (SELECT MAX(c1) FROM T2 WHERE T1.y = T2.c2);

另请参阅

子查询限制

4 - LIKE 模式匹配

Vertica 支持子查询中的 LIKE 模式匹配条件,并采用以下格式:

string-expression [ NOT ] { LIKE | ILIKE | LIKEB | ILIKEB } string-expression

以下命令搜索公司名称以“Ev”开头的客户,然后返回总计数:

=> SELECT COUNT(*) FROM customer_dimension WHERE customer_name LIKE
      (SELECT 'Ev%' FROM customer_dimension LIMIT 1);
 count
-------
   153
(1 row)

Vertica 还支持将单行子查询用作 LIKEB 谓词和 ILIKEB 谓词的模式实参,例如:

=> SELECT * FROM t1 WHERE t1.x LIKEB (SELECT t2.x FROM t2);

以下符号可替代 LIKE 关键字:

~~    LIKE
~#    LIKEB
~~*   ILIKE
~#*   ILIKEB
!~~   NOT LIKE
!~#   NOT LIKEB
!~~*  NOT ILIKE
!~#*  NOT IILIKEB

有关其他示例,请参阅 LIKE 谓词

5 - ANY 和 ALL

您通常只对返回一行的子查询使用比较运算符(=>< 等)。使用 ANYALL 运算符,可在返回多个行的子查询中进行比较。

这些子查询采用以下格式:

expression comparison-operator { ANY | ALL } (subquery)

ANYALL 评估子查询返回的任何或所有值是否与左侧表达式匹配。

等效运算符

可以使用以下运算符代替 ANYALL

Example data

以下示例使用以下表和数据:

ANY 子查询

当在子查询中检索的任何值与左侧表达式的值相匹配时,使用 ANY 关键字的子查询返回 true。

示例

表达式中的 ANY 子查询:

=> SELECT c1, c2 FROM t1 WHERE COALESCE((t1.c1 > ANY (SELECT c1 FROM t2)));
 c1 | c2
----+-----
  2 | fed
  2 | def
  3 | ihg
  3 | ghi
  4 | jkl
  5 | mno
(6 rows)

ANY 不带有聚合的非相关子查询:

=> SELECT c1 FROM t1 WHERE c1 = ANY (SELECT c1 FROM t2) ORDER BY c1;
 c1
----
  1
  1
  2
  2
  3
  3
(6 rows)

ANY 带有聚合的非相关子查询:


=> SELECT c1, c2 FROM t1 WHERE c1 <> ANY (SELECT MAX(c1) FROM t2) ORDER BY c1;
 c1 | c2
----+-----
  1 | cab
  1 | abc
  2 | fed
  2 | def
  4 | jkl
  5 | mno
(6 rows)

=> SELECT c1 FROM t1 GROUP BY c1 HAVING c1 <> ANY (SELECT MAX(c1) FROM t2) ORDER BY c1;
 c1
----
  1
  2
  4
  5
(4 rows)

ANY 带有聚合和 GROUP BY 子句的非相关子查询:


=> SELECT c1, c2 FROM t1 WHERE c1 <> ANY (SELECT MAX(c1) FROM t2 GROUP BY c2) ORDER BY c1;
 c1 | c2
----+-----
  1 | cab
  1 | abc
  2 | fed
  2 | def
  3 | ihg
  3 | ghi
  4 | jkl
  5 | mno
(8 rows)

ANY 带有 GROUP BY 子句的非相关子查询:

=> SELECT c1, c2 FROM t1 WHERE c1 <=> ANY (SELECT c1 FROM t2 GROUP BY c1) ORDER BY c1;
 c1 | c2
----+-----
  1 | cab
  1 | abc
  2 | fed
  2 | def
  3 | ihg
  3 | ghi
(6 rows)

ANY 不带有聚合或 GROUP BY 子句的相关子查询:

=> SELECT c1, c2 FROM t1 WHERE c1 >= ANY (SELECT c1 FROM t2 WHERE t2.c2 = t1.c2) ORDER BY c1;
 c1 | c2
----+-----
  1 | abc
  2 | fed
  4 | jkl
(3 rows)

ALL 子句

当子查询检索到的所有值都与左侧表达式匹配时,使用 ALL 关键字的子查询返回 true,否则返回 false。

示例

ALL 不带有聚合的非相关子查询:

=> SELECT c1, c2 FROM t1 WHERE c1 >= ALL (SELECT c1 FROM t2) ORDER BY c1;
 c1 | c2
----+-----
  3 | ihg
  3 | ghi
  4 | jkl
  5 | mno
(4 rows)

ALL 带有聚合的非相关子查询:

=> SELECT c1, c2 FROM t1 WHERE c1 = ALL (SELECT MAX(c1) FROM t2) ORDER BY c1;
 c1 | c2
----+-----
  3 | ihg
  3 | ghi
(2 rows)

=> SELECT c1 FROM t1 GROUP BY c1 HAVING c1 <> ALL (SELECT MAX(c1) FROM t2) ORDER BY c1;
 c1
----
  1
  2
  4
  5
(4 rows)

ALL 带有聚合和 GROUP BY 子句的非相关子查询:


=> SELECT c1, c2 FROM t1 WHERE c1 <= ALL (SELECT MAX(c1) FROM t2 GROUP BY c2) ORDER BY c1;
 c1 | c2
----+-----
  1 | cab
  1 | abc
(2 rows)

ALL 带有 GROUP BY 子句的非相关子查询:

=> SELECT c1, c2 FROM t1 WHERE c1 <> ALL (SELECT c1 FROM t2 GROUP BY c1) ORDER BY c1;
 c1 | c2
----+-----
  4 | jkl
  5 | mno
(2 rows)

NULL 处理

如果列没有标记为 NOT NULL,则 Vertica 支持多列 <> ALL 子查询。如果任何列包含 NULL 值,Vertica 将返回运行时错误。

如果任何列值为 NULL,则 Vertica 不支持嵌套在另一个表达式中的 = ANY 子查询。

另请参阅

子查询限制

6 - EXISTS 和 NOT EXISTS

EXISTS 谓词是最常见的谓词之一,可用于构建使用非相关和相关子查询的条件。使用 EXISTS 可以不考虑数量就能识别是否存在关系。例如,如果子查询返回任何行,EXISTS 返回 true,如果子查询没有返回行,[NOT] EXISTS 返回 true。

[NOT] EXISTS 子查询采用以下格式:

expression [ NOT ] EXISTS ( subquery )

如果子查询至少返回了一个行,则认为符合 EXISTS 条件。由于结果仅取决于是否返回了记录,而不是取决于这些记录的内容,因此子查询的输出列表通常没有吸引力。常见的编码规范是按照如下方式编写所有 EXISTS 测试:

EXISTS (SELECT 1 WHERE ...)

在上述片段中,SELECT 1 为查询中所有记录返回了值 1。例如,查询返回了五个记录,它会返回 5 个一。系统不会考虑记录中的实际值;它只要知道是否返回了行。

或者,子查询使用 EXISTS 的选择列表可能包含星号 (*)。您不需要指定列名称,因为查询会测试是否有符合子查询中指定条件的记录。

EXISTS (SELECT * WHERE ...)

注意

  • 如果 EXISTS (subquery) 返回至少 1 行,则结果为 TRUE。

  • 如果 EXISTS (subquery) 不返回任何行,则结果为 FALSE。

  • 如果 NOT EXISTS (subquery) 返回至少 1 行,则结果为 FALSE。

  • 如果 NOT EXISTS (subquery) 不返回任何行,则结果为 TRUE。

示例

以下查询检索从任何一家商店购买金额超过 550 美元商品的所有客户的列表:

=> SELECT customer_key, customer_name, customer_state
   FROM public.customer_dimension WHERE EXISTS
     (SELECT 1 FROM store.store_sales_fact
      WHERE customer_key = public.customer_dimension.customer_key
      AND sales_dollar_amount > 550)
   AND customer_state = 'MA' ORDER BY customer_key;
 customer_key |   customer_name    | customer_state
--------------+--------------------+----------------
        14818 | William X. Nielson | MA
        18705 | James J. Goldberg  | MA
        30231 | Sarah N. McCabe    | MA
        48353 | Mark L. Brown      | MA
(4 rows)

使用 EXISTS 子查询还是 IN 子查询,取决于您在外查询块和内查询块中所选择的谓词。例如,要为供应商表中有记录的供应商获取所有商店在 2003 年 1 月 2 日下的所有订单的列表:

=> SELECT store_key, order_number, date_ordered
   FROM store.store_orders_fact WHERE EXISTS
     (SELECT 1 FROM public.vendor_dimension
      WHERE public.vendor_dimension.vendor_key = store.store_orders_fact.vendor_key)
   AND date_ordered = '2012-01-02';
 store_key | order_number | date_ordered
-----------+--------------+--------------
        37 |         2559 | 2012-01-02
        16 |          552 | 2012-01-02
        35 |         1156 | 2012-01-02
        13 |         3885 | 2012-01-02
        25 |          554 | 2012-01-02
        21 |         2687 | 2012-01-02
        49 |         3251 | 2012-01-02
        19 |         2922 | 2012-01-02
        26 |         1329 | 2012-01-02
        40 |         1183 | 2012-01-02
(10 rows)

上述查询查找是否存在下单的供应商和日期。要返回特定的值,而不是简单地确定是否存在,查询需要查找在 2004 年 1 月 4 日达成最佳交易的供应商所下的订单。

=> SELECT store_key, order_number, date_ordered
   FROM store.store_orders_fact ord, public.vendor_dimension vd
   WHERE ord.vendor_key = vd.vendor_key AND vd.deal_size IN
      (SELECT MAX(deal_size) FROM public.vendor_dimension)
    AND date_ordered = '2013-01-04';
 store_key | order_number | date_ordered
-----------+--------------+--------------
       166 |        36008 | 2013-01-04
       113 |        66017 | 2013-01-04
       198 |        75716 | 2013-01-04
        27 |       150241 | 2013-01-04
       148 |       182207 | 2013-01-04
         9 |       188567 | 2013-01-04
        45 |       202416 | 2013-01-04
        24 |       250295 | 2013-01-04
       121 |       251417 | 2013-01-04
(9 rows)

另请参阅

7 - IN 和 NOT IN

尽管无法使一个单值与一个值集相等,但您可以查看单值是否已在此值集中。对多记录单列子查询使用 IN 子句。子查询返回 INNOT IN 产生的结果之后,外查询将利用这些结果来返回最终结果。

[NOT] IN 子查询采用以下格式:

{ expression [ NOT ] IN ( subquery )| expression [ NOT ] IN ( expression ) }

传递给 SELECT 语句的 IN 子句的参数数量不受限制;例如:

=> SELECT * FROM tablename WHERE column IN (a, b, c, d, e, ...);

Vertica 还支持两个或多个外表达式同时引用不同内表达式的查询。

=> SELECT * FROM A WHERE (A.x,A.x) IN (SELECT B.x, B.y FROM B);

示例

以下查询使用 VMart 架构显示了同时引用不同内表达式的外表达式的使用情况:

=> SELECT product_description, product_price FROM product_dimension
   WHERE (product_dimension.product_key, product_dimension.product_key) IN
      (SELECT store.store_orders_fact.order_number,
         store.store_orders_fact.quantity_ordered
       FROM store.store_orders_fact);
 product_description         | product_price
-----------------------------+---------------
 Brand #72 box of candy      |           326
 Brand #71 vanilla ice cream |           270
(2 rows)

要查找马萨诸塞州的商店提供的所有产品,请首先创建内查询,然后运行它以确保它可以正常运行。以下查询返回了马萨诸塞州的所有商店:

=> SELECT store_key FROM store.store_dimension WHERE store_state = 'MA';
 store_key
-----------
        13
        31
(2 rows)

然后创建外查询或主查询,指定在马萨诸塞州的商店售出的所有不同产品。此语句使用 IN 谓词将内查询和外查询组合在一起:

=> SELECT DISTINCT s.product_key, p.product_description
   FROM store.store_sales_fact s, public.product_dimension p
   WHERE s.product_key = p.product_key
       AND s.product_version = p.product_version
       AND s.store_key IN
         (SELECT store_key
          FROM store.store_dimension
          WHERE store_state = 'MA')
   ORDER BY s.product_key;
 product_key |          product_description
-------------+---------------------------------------
           1 | Brand #1 white bread
           1 | Brand #4 vegetable soup
           3 | Brand #9 wheelchair
           5 | Brand #15 cheddar cheese
           5 | Brand #19 bleach
           7 | Brand #22 canned green beans
           7 | Brand #23 canned tomatoes
           8 | Brand #24 champagne
           8 | Brand #25 chicken nuggets
          11 | Brand #32 sausage
         ...   ...
(281 rows)

使用 NOT IN 时,子查询在外查询中返回了一列零值或更多值,其中比较列与子查询返回的任何值都不匹配。使用上一个示例时,NOT IN 返回不是来自马萨诸塞州的所有产品。

注意

如果列没有标记为 NOT NULL,则 Vertica 支持多列 NOT IN 子查询。如果在查询执行期间发现某列中包含 NULL 值,则 Vertica 会返回运行时错误。

同样地,如果任何一个列值为 NULL,则不支持嵌套在另一个表达式中的 IN 子查询。例如,如果在以下语句中,任何一个表的 x 列包含 NULL 值,Vertica 会返回运行时错误:

=> SELECT * FROM t1 WHERE (x IN (SELECT x FROM t2)) IS FALSE;
   ERROR: NULL value found in a column used by a subquery

另请参阅