SQL:在字段名前加上子查询标识符是否会强制首先评估子查询?
SQL: does prepending a field name with a subquery identifier enforce the subquery to be evaluated first?
我的问题不是了解在以下查询中发生了什么(可能在不同的实现中)。
相反,它是关于了解 SQL 标准是否定义了正确的行为应该是什么。
一个简单的 table 负整数和正整数:
CREATE TABLE x (n INTEGER);
INSERT INTO x VALUES (-2);
INSERT INTO x VALUES (-1);
INSERT INTO x VALUES (0);
INSERT INTO x VALUES (1);
INSERT INTO x VALUES (2);
先做这个查询:
select n
from x
where n <> 0
and 1/n = 1;
显然,人们期望的智能评估顺序与查询中所写的完全相同,以避免计算 1/0,这会导致错误。
但是,SQL 是一种声明性查询语言,正如在几个问题中已经探讨的那样,where 子句的顺序无关紧要,因此可以按任何顺序对其进行求值,这意味着除以 0 错误可能发生并且会没事的。很清楚了。
现在第二个例子:
select nonzero.n
from (select n from x where n <> 0) as nonzero
where 1/nonzero.n = 1;
这在 table x
上的 where 子句在逻辑上是相同的,但它们的组织方式不同。
这次我定义了一个不能有 0 的关系。主查询显式计算 1/nonzero.n
,所以我直觉地希望引擎在这里强制执行计算顺序,并且看不到任何除以 0.
请注意,这不是我在实践中看到的唯一评估选项。一些 SQL 引擎会首先将第二个查询扁平化回第一个。
不管不同的实现是什么,我的问题是:SQL 标准是否以任何方式强制执行,当我写 nonzero.n
然后 n
真的取自关系 nonzero
而不是来自 x
,这显然不等价?
如果是这样,您知道正式表达的任何指针吗?
标准没有具体说明要做什么。错误处理能力较弱
更重要的是,该标准非常明确,不强制执行表达式和查询组件的计算顺序——子查询或 select
中的表达式没有顺序。整个查询描述了结果集 -- 而不是创建结果集的分步说明。
这是故意的。编写标准的人都知道执行计划通常是一个有向无环图 (DAG),它与原始查询无关(除了实现它!)。
请注意,在某些情况下 1/0
根本不会被评估。一些数据库访问:
where exists (select 1 / 0
from t
where . . .
)
Exists 只关心是否返回行,而不关心那些行上的值是什么。
我的问题不是了解在以下查询中发生了什么(可能在不同的实现中)。 相反,它是关于了解 SQL 标准是否定义了正确的行为应该是什么。
一个简单的 table 负整数和正整数:
CREATE TABLE x (n INTEGER);
INSERT INTO x VALUES (-2);
INSERT INTO x VALUES (-1);
INSERT INTO x VALUES (0);
INSERT INTO x VALUES (1);
INSERT INTO x VALUES (2);
先做这个查询:
select n
from x
where n <> 0
and 1/n = 1;
显然,人们期望的智能评估顺序与查询中所写的完全相同,以避免计算 1/0,这会导致错误。
但是,SQL 是一种声明性查询语言,正如在几个问题中已经探讨的那样,where 子句的顺序无关紧要,因此可以按任何顺序对其进行求值,这意味着除以 0 错误可能发生并且会没事的。很清楚了。
现在第二个例子:
select nonzero.n
from (select n from x where n <> 0) as nonzero
where 1/nonzero.n = 1;
这在 table x
上的 where 子句在逻辑上是相同的,但它们的组织方式不同。
这次我定义了一个不能有 0 的关系。主查询显式计算 1/nonzero.n
,所以我直觉地希望引擎在这里强制执行计算顺序,并且看不到任何除以 0.
请注意,这不是我在实践中看到的唯一评估选项。一些 SQL 引擎会首先将第二个查询扁平化回第一个。
不管不同的实现是什么,我的问题是:SQL 标准是否以任何方式强制执行,当我写 nonzero.n
然后 n
真的取自关系 nonzero
而不是来自 x
,这显然不等价?
如果是这样,您知道正式表达的任何指针吗?
标准没有具体说明要做什么。错误处理能力较弱
更重要的是,该标准非常明确,不强制执行表达式和查询组件的计算顺序——子查询或 select
中的表达式没有顺序。整个查询描述了结果集 -- 而不是创建结果集的分步说明。
这是故意的。编写标准的人都知道执行计划通常是一个有向无环图 (DAG),它与原始查询无关(除了实现它!)。
请注意,在某些情况下 1/0
根本不会被评估。一些数据库访问:
where exists (select 1 / 0
from t
where . . .
)
Exists 只关心是否返回行,而不关心那些行上的值是什么。