类别:

查询语法

WHERE

WHERE 子句指定了一个充当筛选器的条件。您可以使用 WHERE 子句执行以下操作:

语法

...
WHERE <predicate>
[ ... ]
Copy
predicate

布尔表达式。该表达式可以包含 逻辑运算符,如 ANDORNOT

使用说明

  • WHERE 子句中的谓词表现得就像是在 FROM 子句之后计算的一样(尽管优化器可以在不影响结果的情况下对谓词进行重新排序)。例如,如果 WHERE 子句中的谓词引用了参与 FROM 子句外部联接的表的列,则筛选器将对联接返回的行(可能用 NULLs 填充)进行操作。

  • 创建可能计算 NULLs 的表达式时要小心。

    • 在大多数上下文中,布尔表达式 NULL = NULL 返回 NULL,而不是 TRUE。考虑使用 IS [ NOT ] NULL 来比较 NULL 值。

    • WHERE 子句中,如果表达式的计算结果为 NULL,则从结果集中移除该表达式的行(即筛选掉该行)。

  • 列表中的最大表达式数量为 16,384。例如,该限制适用于以下 SELECT 语句中的表达式数量:

    SELECT column_x
       FROM mytable
       WHERE column_y IN (<expr1>, <expr2>, <expr3> ...);
    
    Copy

    为避免达到限制,请使用包含表达式值的查找表执行联接,而不是使用 IN 子句指定值。例如,当上一示例中的表达式值添加到名为 mylookuptable 的查找表时,即使查找表的行数超过 16,384 行,也可以成功运行以下查询:

    SELECT column_x
      FROM mytable t
      JOIN mylookuptable l
      ON t.column_y = l.values_for_comparison;
    
    Copy

WHERE 子句中的联接

虽然 WHERE 子句主要用于筛选,但是 WHERE 子句也可以用于表示多种类型的联接。有关联接的概念信息,请参阅 使用联接

WHERE 子句可以通过包含联接条件来指定联接,联接条件是布尔表达式,用于定义 JOIN 一端的哪些行与联接另一端的哪些行相匹配。

以下两个等效查询显示了如何在 WHEREFROM 子句中表达内部联接:

SELECT t1.c1, t2.c2
    FROM t1, t2
    WHERE t1.c1 = t2.c2;

SELECT t1.c1, t2.c2
    FROM t1 INNER JOIN t2
        ON t1.c1 = t2.c2;
Copy

可以通过在 WHERE 子句中使用 (+) 语法或在 FROM 子句中使用 OUTER JOIN 关键字来指定外部联接。

当您用 (+) 指定外部联接时, WHERE 子句将 (+) 应用于表的每个“内部”联接列(定义如下)。

备注

外部联接的结果包含一个表中所有行的副本。在本主题中,保留行的表称为“外部”表,另一个表称为“内部”表。

  • 在 LEFT OUTER JOIN 中,左边的表是外部表,右边的表是内部表。

  • 在 RIGHT OUTER JOIN 中,右边的表是外部表,左边的表是内部表。

以下查询显示等效的左外部联接,其中一个指定 FROM 子句中的联接,另一个指定 WHERE 子句中的联接:

SELECT t1.c1, t2.c2
FROM t1 LEFT OUTER JOIN t2
        ON t1.c1 = t2.c2;

SELECT t1.c1, t2.c2
FROM t1, t2
WHERE t1.c1 = t2.c2(+);
Copy

在第二个查询中, (+) 位于右侧,用于标识内部表。

这两个查询的输出示例如下:

+-------+-------+
| T1.C1 | T2.C2 |
|-------+-------|
|     1 |     1 |
|     2 |  NULL |
|     3 |     3 |
|     4 |  NULL |
+-------+-------+
Copy

如果要在多个列上联接一个表,请在内部表的 每个 列上使用 (+) 符号(以下示例中的 t2 ):

SELECT t1.c1, t2.c2
FROM t1, t2
WHERE t1.c1 = t2.c2 (+)
  AND t1.c3 = t2.c4 (+);
Copy

备注

(+) 符号的出现位置有许多限制; FROM 子句外部联接更具表现力。Snowflake 建议只有在移植已经使用了符号 (+) 的代码时才使用该符号。新代码应避免使用这种符号。

限制包括:

  • 不能使用 (+) 符号创建 FULL OUTER JOIN;只能创建 LEFT OUTER JOINRIGHT OUTER JOIN。以下内容 效。该语句会导致以下错误消息: SQL compilation error: Outer join predicates form a cycle between 'T1' and 'T2'.

    -- NOT VALID
    select t1.c1
        from t1, t2
        where t1.c1 (+) = t2.c2 (+);
    
    Copy
  • 如果一个表参与一个查询中的多个联接,则 (+) 符号只能将该表指定为其中 一个 联接中的内部表。以下内容 效,因为 t1 在两个联接中充当内部表。该语句会导致以下错误消息: SQL compilation error: Table 'T1' is outer joined to multiple tables: 'T3' and 'T2'.

    -- NOT VALID
    select t1.c1
        from t1, t2, t3
        where t1.c1 (+) = t2.c2
          and t1.c1 (+) = t3.c3;
    
    Copy

    但是请注意,您可以使用 (+)不同的表 标识为同一 SQL 语句中 不同联接 的内部表。以下示例联接三个表:t1t2t3,其中两个是内部表(在不同的联接中)。此语句执行以下操作:

    • t1t2 之间的 LEFT OUTER JOIN(其中 t2 是内部表)。

    • t2t3 之间的 LEFT OUTER JOIN(其中 t3 是内部表)。

    select t1.c1
        from t1, t2, t3
        where t1.c1 = t2.c2 (+)
          and t2.c2 = t3.c3 (+);
    
    Copy

(+) 可以紧邻表名和列名,也可以用空格分隔。以下两项均有效:

where t1.c1 = t2.c2(+)

where t1.c1 = t2.c2 (+)
Copy

查询可以包含在 FROM ... ON ... 子句和 WHERE 子句中指定的联接。但是,在同一查询的不同子句中指定联接会使该查询更难读取。

WHERE 子句中对联接的支持主要是为了向后兼容不使用 FROM ... ON ... 语法的旧查询。Snowflake 建议在编写带有联接的新查询时使用 FROM ... ON ...。有关详细信息,请参阅 JOIN

示例

筛选的简单示例

以下显示了 WHERE 子句的一些简单用法:

SELECT * FROM invoices
  WHERE invoice_date < '2018-01-01';

SELECT * FROM invoices
  WHERE invoice_date < '2018-01-01'
    AND paid = FALSE;
Copy

此示例使用子查询,显示所有账单金额小于平均水平的发票:

SELECT * FROM invoices
    WHERE amount < (
                   SELECT AVG(amount)
                       FROM invoices
                   )
    ;
Copy

在 WHERE 子句中执行联接

要在 WHERE 子句中指定联接,请在 FROM clause 中列出要联接的表,用逗号分隔这些表。在 WHERE 子句中将联接条件指定为筛选器,如下例所示:

SELECT t1.col1, t2.col1
    FROM t1, t2
    WHERE t2.col1 = t1.col1
    ORDER BY 1, 2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
+------+------+
Copy

备注

逗号运算符是 INNER JOIN 的旧语法。以下语句显示了使用较新语法执行联接的推荐方法。下面的查询等同于上面的查询:

SELECT t1.col1, t2.col1
    FROM t1 JOIN t2
        ON t2.col1 = t1.col1
    ORDER BY 1, 2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
+------+------+
Copy

下一节将展示 3 表联接,并展示 0、1 或 2 (+) 外部联接运算符的行为差异。

在执行查询之前,创建并加载要在联接中使用的表:

create table departments (
    department_ID INTEGER,
    department_name VARCHAR,
    location VARCHAR
    );
insert into departments (department_id, department_name, location) values
    (10, 'CUSTOMER SUPPORT', 'CHICAGO'),
    (40, 'RESEARCH', 'BOSTON'),
    (80, 'Department with no employees yet', 'CHICAGO'),
    (90, 'Department with no projects or employees yet', 'EREHWON')
    ;

create table projects (
    project_id integer,
    project_name varchar,
    department_id integer
    );
insert into projects (project_id, project_name, department_id) values
    (4000, 'Detect fake product reviews', 40),
    (4001, 'Detect false insurance claims', 10),
    (9000, 'Project with no employees yet', 80),
    (9099, 'Project with no department or employees yet', NULL)
    ;

create table employees (
    employee_ID INTEGER,
    employee_name VARCHAR,
    department_id INTEGER,
    project_id INTEGER
    );
insert into employees (employee_id, employee_name, department_id, project_id)
  values
    (1012, 'May Aidez', 10, NULL),
    (1040, 'Devi Nobel', 40, 4000),
    (1041, 'Alfred Mendeleev', 40, 4001)
    ;
Copy

执行 3 向内部联接。这不使用 (+) (或 OUTER 关键字),因此是一个内部联接。输出仅包括有部门、项目和员工的行:

SELECT d.department_name, p.project_name, e.employee_name
    FROM  departments d, projects p, employees e
    WHERE
            p.department_id = d.department_id
        AND
            e.project_id = p.project_id
    ORDER BY d.department_id, p.project_id, e.employee_id;
+------------------+-------------------------------+------------------+
| DEPARTMENT_NAME  | PROJECT_NAME                  | EMPLOYEE_NAME    |
|------------------+-------------------------------+------------------|
| CUSTOMER SUPPORT | Detect false insurance claims | Alfred Mendeleev |
| RESEARCH         | Detect fake product reviews   | Devi Nobel       |
+------------------+-------------------------------+------------------+
Copy

执行外部联接。除了 使用 (+) 使第二个联接成为右外部联接之外,这与前面的语句类似。其效果是,如果某个部门包含在输出中,则该部门的所有项目都将包括在内,即使这些项目没有员工:

SELECT d.department_name, p.project_name, e.employee_name
    FROM  departments d, projects p, employees e
    WHERE
            p.department_id = d.department_id
        AND
            e.project_id(+) = p.project_id
    ORDER BY d.department_id, p.project_id, e.employee_id;
+----------------------------------+-------------------------------+------------------+
| DEPARTMENT_NAME                  | PROJECT_NAME                  | EMPLOYEE_NAME    |
|----------------------------------+-------------------------------+------------------|
| CUSTOMER SUPPORT                 | Detect false insurance claims | Alfred Mendeleev |
| RESEARCH                         | Detect fake product reviews   | Devi Nobel       |
| Department with no employees yet | Project with no employees yet | NULL             |
+----------------------------------+-------------------------------+------------------+
Copy

执行两个外部联接。这与前面的语句相同, 只是 它使用 (+) 将两个联接都变成外部联接。结果是所有部门都包括在内(即使他们还没有项目或员工),所有与部门相关的项目都包括在内(即使他们还没有员工)。请注意,输出不包括没有部门的项目。

SELECT d.department_name, p.project_name, e.employee_name
    FROM  departments d, projects p, employees e
    WHERE
            p.department_id(+) = d.department_id
        AND
            e.project_id(+) = p.project_id
    ORDER BY d.department_id, p.project_id, e.employee_id;
+----------------------------------------------+-------------------------------+------------------+
| DEPARTMENT_NAME                              | PROJECT_NAME                  | EMPLOYEE_NAME    |
|----------------------------------------------+-------------------------------+------------------|
| CUSTOMER SUPPORT                             | Detect false insurance claims | Alfred Mendeleev |
| RESEARCH                                     | Detect fake product reviews   | Devi Nobel       |
| Department with no employees yet             | Project with no employees yet | NULL             |
| Department with no projects or employees yet | NULL                          | NULL             |
+----------------------------------------------+-------------------------------+------------------+
Copy

(但是,请记住,Snowflake 建议在 FROM 子句中使用 OUTER 关键字,而不是在 WHERE 子句中使用 (+) 运算符。)

语言: 中文