- 类别:
WHERE¶
WHERE
子句指定了一个充当筛选器的条件。您可以使用 WHERE
子句执行以下操作:
语法¶
...
WHERE <predicate>
[ ... ]
predicate
布尔表达式。该表达式可以包含 逻辑运算符,如
AND
、OR
和NOT
。
使用说明¶
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> ...);
为避免达到限制,请使用包含表达式值的查找表执行联接,而不是使用 IN 子句指定值。例如,当上一示例中的表达式值添加到名为
mylookuptable
的查找表时,即使查找表的行数超过 16,384 行,也可以成功运行以下查询:SELECT column_x FROM mytable t JOIN mylookuptable l ON t.column_y = l.values_for_comparison;
WHERE 子句中的联接¶
虽然 WHERE
子句主要用于筛选,但是 WHERE
子句也可以用于表示多种类型的联接。有关联接的概念信息,请参阅 使用联接。
WHERE
子句可以通过包含联接条件来指定联接,联接条件是布尔表达式,用于定义 JOIN 一端的哪些行与联接另一端的哪些行相匹配。
以下两个等效查询显示了如何在 WHERE
或 FROM 子句中表达内部联接:
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;
可以通过在 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(+);
在第二个查询中, (+)
位于右侧,用于标识内部表。
这两个查询的输出示例如下:
+-------+-------+ | T1.C1 | T2.C2 | |-------+-------| | 1 | 1 | | 2 | NULL | | 3 | 3 | | 4 | NULL | +-------+-------+
如果要在多个列上联接一个表,请在内部表的 每个 列上使用 (+)
符号(以下示例中的 t2
):
SELECT t1.c1, t2.c2 FROM t1, t2 WHERE t1.c1 = t2.c2 (+) AND t1.c3 = t2.c4 (+);备注
(+)
符号的出现位置有许多限制; FROM 子句外部联接更具表现力。Snowflake 建议只有在移植已经使用了符号(+)
的代码时才使用该符号。新代码应避免使用这种符号。限制包括:
不能使用
(+)
符号创建FULL OUTER JOIN
;只能创建LEFT OUTER JOIN
和RIGHT 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 (+);如果一个表参与一个查询中的多个联接,则
(+)
符号只能将该表指定为其中 一个 联接中的内部表。以下内容 无 效,因为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;但是请注意,您可以使用
(+)
将 不同的表 标识为同一 SQL 语句中 不同联接 的内部表。以下示例联接三个表:t1
、t2
和t3
,其中两个是内部表(在不同的联接中)。此语句执行以下操作:
t1
和t2
之间的 LEFT OUTER JOIN(其中t2
是内部表)。
t2
和t3
之间的 LEFT OUTER JOIN(其中t3
是内部表)。select t1.c1 from t1, t2, t3 where t1.c1 = t2.c2 (+) and t2.c2 = t3.c3 (+);
(+)
可以紧邻表名和列名,也可以用空格分隔。以下两项均有效:
where t1.c1 = t2.c2(+) where t1.c1 = t2.c2 (+)
查询可以包含在 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;
此示例使用子查询,显示所有账单金额小于平均水平的发票:
SELECT * FROM invoices WHERE amount < ( SELECT AVG(amount) FROM invoices ) ;
在 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 | +------+------+
备注
逗号运算符是 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 | +------+------+
下一节将展示 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) ;执行 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 | +------------------+-------------------------------+------------------+执行外部联接。除了 使用
(+)
使第二个联接成为右外部联接之外,这与前面的语句类似。其效果是,如果某个部门包含在输出中,则该部门的所有项目都将包括在内,即使这些项目没有员工: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 | +----------------------------------+-------------------------------+------------------+执行两个外部联接。这与前面的语句相同, 只是 它使用
(+)
将两个联接都变成外部联接。结果是所有部门都包括在内(即使他们还没有项目或员工),所有与部门相关的项目都包括在内(即使他们还没有员工)。请注意,输出不包括没有部门的项目。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 | +----------------------------------------------+-------------------------------+------------------+
(但是,请记住,Snowflake 建议在 FROM
子句中使用 OUTER
关键字,而不是在 WHERE
子句中使用 (+)
运算符。)