EXISTS 和 IN 的 Spark 替换
Spark replacement for EXISTS and IN
我正在尝试 运行 使用 EXIST 子句的查询:
select <...>
from A, B, C
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
exists (select A.ID from <subquery 1>) or
exists (select A.ID from <subquery 2>)
很遗憾,这似乎不受支持。我还尝试用 IN
子句替换 EXISTS
子句:
select <...>
from A, B, C
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID in (select ID from ...) or
A.ID in (select ID from ...)
不幸的是,IN
子句似乎也不受支持。
关于如何编写 SQL 查询以达到预期结果的任何想法?原则上我可以将 WHERE
子句建模为另一个 JOIN
并将第二个 OR
子句建模为 UNION
但它看起来超级笨拙..
编辑:列出许多可能的解决方案。
解决方案 1
select <...>
from A, B, C
(select ID from ...) as exist_clause_1,
(select ID from ...) as exist_clause_2,
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = exist_clause_1.ID or
A.ID = exist_clause_2.ID
解决方案 2
select <...>
from A, B, C
( (select ID from ...) UNION
(select ID from ...)
) as exist_clause,
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = exist_clause.ID
SparkSQL 目前没有 EXISTS & IN。 "(Latest) Spark SQL / DataFrames and Datasets Guide / Supported Hive Features"
EXISTS & IN 总是可以使用 JOIN 或 LEFT SEMI JOIN 重写。 "Although Apache Spark SQL currently does not support IN or EXISTS subqueries, you can efficiently implement the semantics by rewriting queries to use LEFT SEMI JOIN." OR 总是可以使用 UNION 重写。 AND NOT 可以用 EXCEPT 重写。
A table 保存使某些 谓词 (由列名参数化的语句)为真:
的行
- DBA 给出了每个基 table
T
的谓词,列为 T.C,...
: T(T.C,...)
- A
JOIN
保存使其参数谓词的 AND 为真的行;对于 UNION
,OR;对于 EXCEPT
,AND NOT。
SELECT DISTINCT
kept columns
FROM
T
保存 EXISTS 所在的行删除的列 [T 的谓词]。
T
LEFT SEMI JOIN
U
保存 EXISTS 所在的行U-only 列 [T 的谓词 AND U 的谓词]。
T
WHERE
condition
保存 predicate 所在的行T AND 条件。
(重新查询一般见this answer。)
因此,通过记住对应于 SQL 的谓词表达式,您可以使用简单的逻辑重写规则来编写 and/or 重组查询。例如,就可读性或执行而言,此处使用 UNION 不需要 "clumsy"。
您的原始问题表明您了解可以使用 UNION 并且您已将变体编辑到您的问题中,从您的原始查询中删除 EXISTS 和 IN。这是另一个也删除 OR 的变体。
select <...>
from A, B, C, (select ID from ...) as e
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = e.id
union
select <...>
from A, B, C, (select ID from ...) as e
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = e.ID
您的解决方案 1 与您认为的不同。如果 exists_clause
table 中只有一个是空的,即即使在另一个中有 ID
匹配可用,tables 的 FROM 叉积是空的并且没有行被返回。 ("An Unintuitive Consequence of SQL Semantics": Chapter 6 The Database Language SQL sidebar page 264 of Database Systems: The Complete Book 2nd Edition.) FROM 不只是为 table 的行引入名称,它是 CROSS JOINing and/or OUTER JOINing 它们,然后 ON(对于 INNER JOIN)和 WHERE 过滤掉一些。
返回相同行的不同表达式的性能通常不同。这取决于 DBMS 优化。许多细节,DBMS and/or 程序员可能知道,如果知道也可能不知道,可能会或可能不会最好地平衡,影响评估查询的最佳方式和编写查询的最佳方式。但是在 WHERE 中每行执行两个 ORed 子选择(如在您的原始查询中以及您后期的解决方案 2 中)不一定优于 运行 两个 SELECT 的一个 UNION(如在我的查询中)。
我正在尝试 运行 使用 EXIST 子句的查询:
select <...>
from A, B, C
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
exists (select A.ID from <subquery 1>) or
exists (select A.ID from <subquery 2>)
很遗憾,这似乎不受支持。我还尝试用 IN
子句替换 EXISTS
子句:
select <...>
from A, B, C
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID in (select ID from ...) or
A.ID in (select ID from ...)
不幸的是,IN
子句似乎也不受支持。
关于如何编写 SQL 查询以达到预期结果的任何想法?原则上我可以将 WHERE
子句建模为另一个 JOIN
并将第二个 OR
子句建模为 UNION
但它看起来超级笨拙..
编辑:列出许多可能的解决方案。
解决方案 1
select <...>
from A, B, C
(select ID from ...) as exist_clause_1,
(select ID from ...) as exist_clause_2,
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = exist_clause_1.ID or
A.ID = exist_clause_2.ID
解决方案 2
select <...>
from A, B, C
( (select ID from ...) UNION
(select ID from ...)
) as exist_clause,
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = exist_clause.ID
SparkSQL 目前没有 EXISTS & IN。 "(Latest) Spark SQL / DataFrames and Datasets Guide / Supported Hive Features"
EXISTS & IN 总是可以使用 JOIN 或 LEFT SEMI JOIN 重写。 "Although Apache Spark SQL currently does not support IN or EXISTS subqueries, you can efficiently implement the semantics by rewriting queries to use LEFT SEMI JOIN." OR 总是可以使用 UNION 重写。 AND NOT 可以用 EXCEPT 重写。
A table 保存使某些 谓词 (由列名参数化的语句)为真:
的行- DBA 给出了每个基 table
T
的谓词,列为T.C,...
: T(T.C,...) - A
JOIN
保存使其参数谓词的 AND 为真的行;对于UNION
,OR;对于EXCEPT
,AND NOT。 SELECT DISTINCT
kept columns
FROM
T
保存 EXISTS 所在的行删除的列 [T 的谓词]。T
LEFT SEMI JOIN
U
保存 EXISTS 所在的行U-only 列 [T 的谓词 AND U 的谓词]。T
WHERE
condition
保存 predicate 所在的行T AND 条件。
(重新查询一般见this answer。)
因此,通过记住对应于 SQL 的谓词表达式,您可以使用简单的逻辑重写规则来编写 and/or 重组查询。例如,就可读性或执行而言,此处使用 UNION 不需要 "clumsy"。
您的原始问题表明您了解可以使用 UNION 并且您已将变体编辑到您的问题中,从您的原始查询中删除 EXISTS 和 IN。这是另一个也删除 OR 的变体。
select <...>
from A, B, C, (select ID from ...) as e
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = e.id
union
select <...>
from A, B, C, (select ID from ...) as e
where
A.FK_1 = B.PK and
A.FK_2 = C.PK and
A.ID = e.ID
您的解决方案 1 与您认为的不同。如果 exists_clause
table 中只有一个是空的,即即使在另一个中有 ID
匹配可用,tables 的 FROM 叉积是空的并且没有行被返回。 ("An Unintuitive Consequence of SQL Semantics": Chapter 6 The Database Language SQL sidebar page 264 of Database Systems: The Complete Book 2nd Edition.) FROM 不只是为 table 的行引入名称,它是 CROSS JOINing and/or OUTER JOINing 它们,然后 ON(对于 INNER JOIN)和 WHERE 过滤掉一些。
返回相同行的不同表达式的性能通常不同。这取决于 DBMS 优化。许多细节,DBMS and/or 程序员可能知道,如果知道也可能不知道,可能会或可能不会最好地平衡,影响评估查询的最佳方式和编写查询的最佳方式。但是在 WHERE 中每行执行两个 ORed 子选择(如在您的原始查询中以及您后期的解决方案 2 中)不一定优于 运行 两个 SELECT 的一个 UNION(如在我的查询中)。