此查询的正确结果是什么?


20

在这里的评论中遇到了这个难题

CREATE TABLE r (b INT);

SELECT 1 FROM r HAVING 1=1;

SQL ServerPostgreSQL返回1行。

MySQLOracle返回零行。

哪个是对的?还是两者都有效?


好难题。我认为正确的是返回1行。SQL-Server本身矛盾,因为它SELECT COUNT(*) FROM r;返回1行(带有0),而不SELECT COUNT(*) FROM r GROUP BY ();返回任何行。
ypercubeᵀᴹ

1
想要更多?SELECT 1 WHERE 1=0 HAVING 1=1;SQL ServerPostgreSQL仍返回一行。Oracle需要 FROM DUAL,并且不返回任何行。MySQL既不使用FROM DUAL也不进行编译。
Andriy M

1
@AndriyM由于某些未知原因,“ dual”和“ HAVING”在MySQL中不能很好地发挥作用。(很好的发现)。但是等效的方法是:SELECT 1 AS t FROM (SELECT 1) tmp WHERE 1=0 HAVING 1=1; 1行无双,并返回0行。
ypercubeᵀᴹ

1
@SQLKiwi-规范中的这段内容呢?“如果TE不立即包含<group by clause>“GROUP BY ()”则为隐式。”。那两个查询不应该返回相同的结果吗?
马丁·史密斯

1
但不同意这些(甲骨文执行与查询HAVING不同):SQL的小提琴2:HAVING使事情变得不同
ypercubeᵀᴹ

Answers:


17

按照标准:

SELECT 1 FROM r HAVING 1=1

手段

SELECT 1 FROM r GROUP BY () HAVING 1=1

引用ISO / IEC 9075-2:2011 7.10语法规则1(HAVING子句的定义的一部分):

让它HC成为<having clause>。让TE<table expression>直接包含HC。如果TE不立即包含 <group by clause>,则“ GROUP BY ()”是隐含的。我们T是由定义的表的描述符<group by clause> GBC直接包含在TER是的结果GBC

好的,这很清楚。


断言:1=1是真实的搜索条件。我不会为此提供任何引用。


现在

SELECT 1 FROM r GROUP BY () HAVING 1=1

等价于

SELECT 1 FROM r GROUP BY ()

引用ISO / IEC 9075-2:2011 7.10一般规则1:

<search condition>对各组的评价R。的结果<having clause>是R的那些组的分组表,其结果 <search condition>为True。

逻辑:由于搜索条件始终为true,因此结果为R,这是按表达式分组的结果。


以下摘录自7.9一般规则(GROUP BY CLAUSE的定义)

1)如果未<where clause>指定,则T设为前面的结果<from clause>;否则,T设为的结果<where clause>

2)案例:

a)如果没有分组列,则的结果<group by clause>就是T作为唯一分组组成的分组表。

因此我们可以得出结论

FROM r GROUP BY ()

生成一个分组的表,该表由一组组成,具有零行(因为R为空)。


摘录自7.12的通用规则,其中定义了查询规范(又称为SELECT语句):

1)案例:

a)如果T不是分组表,则[...]

b)如果T是分组表,则

案件:

i)如果T有0(零)个组,则让TEMP为空表。

ⅱ)如果T有一个或多个基团,则每个<value expression>被施加到每个组的T产生的表TEMPM行,其中M是在基团的数目TiTEMP 的-th列包含通过i-th 求值得出的值<value expression>。[...]

2)案例:

a)如果<set quantifier> DISTINCT未指定,则结果<query specification>TEMP

因此,由于该表具有一组,因此它必须具有一个结果行。

从而

SELECT 1 FROM r HAVING 1=1

应该返回1行结果集。

优质教育


+1感谢您解决所有麻烦!就像@ypercube所说的那样,SQL Server似乎与SELECT 1 FROM r GROUP BY()矛盾。返回零行,但是您引用的段落在这一点上似乎很清楚。
马丁·史密斯

请问您在哪里找到标准?如果您说“在我的书架上”,我会很失望的:)
dezso

从技术上讲,我使用最终草案国际标准,而不是标准本身。根据ISO / IEC规则,仅允许在FDIS和最终标准之间进行编辑性(非技术性)更改。该标准分为多个部分。第1部分第2部分第4部分 ...
Kevin Cathcart

第11 部分第14部分。第3、9、10和13部分在2011年未更新,因此适用其先前版本。没有第12部分。类似地,没有第5-8部分。有关每个部分包含的内容,请参见Wikipedia页面上的Sql:2011或第1部分本身。
凯文·卡斯卡特

7

HAVING子句但无WHERE子句时:

SELECT 1 FROM r HAVING 1=1;

...然后GROUP BY ()是隐式的。因此,查询应等效于:

SELECT 1 FROM r GROUP BY () HAVING 1=1;

...应该将表的所有行分组为一组(即使表根本没有行-它仍然是一组0行)并返回1行。之后,HAVING具有True条件的完全不起作用。


从不同的角度来看,这样的查询应该返回多少行?

SELECT COUNT(*), MAX(b) FROM r;

一,零或“零或一,取决于表是否为空”?

我想一行,无论有多少行r


好吧,关键问题是“即使表根本没有行,它仍然是一组0行”是否确实如此。该标准对此非常明确:“如果没有分组列,则...是由T作为唯一组的分组表”。(即使T为空,它仍然成立-因此确实存在一个组。)此外,having子句指定将条件应用于每个组(在此示例中为一次)。他们可能以这种方式定义它,以使SUM和COUNT即使是空T也返回一行。
Erwin Smout,2013年

+1(更早!)尽管您的逻辑与Kevin的相同,但由于规范中的引用,我接受了他的回答。谢谢!
马丁·史密斯

@MartinSmith。谢谢 我从懒惰:)让
ypercubeᵀᴹ

@ypercube:我也+1。我决定花更多时间从规范中抽出证据,以证明没有隐藏在任何地方的狡猾的单词会导致您的答案错误。但是一旦完成,我不妨将其作为完整答案发布。所以我做了。
凯文·卡斯卡特

3
@ErwinSmout:当然不是。但是,根据美国版权法,这属于合理使用范围。出于教育目的,在对作品进行分析(即批评)的上下文中引用的相对较小的部分,对作品的销售能力影响可忽略不计。
凯文·卡斯卡特

3

从我看来,SQLServer和PostgerSQL根本不用理会表:

CREATE TABLE r (b INT);
insert into r(b) values (1);
insert into r(b) values (2);
SELECT 1 FROM r HAVING 1=1;

也只返回一行。即使SQLServer文档

如果不使用GROUP BY,则HAVING的行为类似于WHERE子句。

在这种情况下是不正确的- WHERE 1=1而不是HAVING返回正确的行数。我会说这是优化程序错误(或至少是文档错误)... SQLServer计划显示“恒定扫描”以防万一,HAVING“表扫描”显示WHERE...

对我来说,Oracle和Mysql的行为似乎更合乎逻辑且正确。


1
没错,SQL Server不会查看表。执行计划只是进行不间断的扫描,甚至不引用表。如果只是SQL Server,我会把它归结为一个错误,但不仅仅是SQL Server,我想知道这里是否存在真正的歧义。
马丁·史密斯,

PostgreSQL显示与SQLServer相同的结果,据我从输出explain“ Result(rows = 1)...”获得的结果以及“ Seq Scan”获得“ WHERE”的结果,它也没有查询表。 ..我想这与“ FROM”在TSQL和PostgreSQL中不是强制性的事实有关。我知道Mysql也不需要它,但是由于它们支持dual,所以它们解析查询的方式可能有所不同。我同意,这听起来像是一种猜测,但我希望这是有道理的。
2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.