为什么这个带有子查询的SQL查询要求限制为单个值的列使用GROUP BY?
为什么下面的SQL查询失败为什么这个带有子查询的SQL查询要求限制为单个值的列使用GROUP BY?,sql,sql-server,Sql,Sql Server,为什么下面的SQL查询失败 SELECT a.time, SUM(a.x)*(SELECT SUM(b.weight) FROM b WHERE b.id = a.id AND b.time = a.time) AS z FROM a WHERE a.id = 'FOO' GROUP BY a.time 对于SQL Server 2016,我遇到了一个错误 Msg 8120,第16级,状态1,第9行 列“a.id”在选择列表中无效,因为它未包含在聚合
SELECT
a.time,
SUM(a.x)*(SELECT SUM(b.weight) FROM b WHERE b.id = a.id AND b.time = a.time) AS z
FROM
a
WHERE
a.id = 'FOO'
GROUP BY
a.time
对于SQL Server 2016,我遇到了一个错误
Msg 8120,第16级,状态1,第9行列“a.id”在选择列表中无效,因为它未包含在聚合函数或GROUP BY子句中 该错误消息意味着SQL Server认为内部查询可以为多个
a.id
生成结果,因此它不知道生成哪一个。我不明白它为什么会这样想,因为外部查询的WHERE
将a.id
限制为单个值
我可以通过将a.id
添加到外部查询的groupby
,或者在内部查询中将a.id
替换为'FOO'
来消除错误。在我的应用程序中,这两种查询都是不可取的,其中许多查询都是从预制件动态创建的,内部查询最好是固定的(即,不动态插入literal'FOO'
),外部查询最好不知道内部查询的细节(即,不能仅仅因为内部查询使用了a.id
而将a.id
添加到外部查询的groupby
)
在不让内部查询和外部查询更加了解彼此的细节的情况下,是否可以解决此问题
编辑:
time
和id
字段是这两个表的主键的一部分。我很想看看是否有人有更好的解决方案,但我过去也做过类似的事情来解决类似的问题
SELECT
a.time,
SUM(a.x)*(SELECT SUM(b.weight) FROM b WHERE b.id = MIN(a.id) AND b.time = a.time) AS z
FROM a
WHERE
a.id='FOO'
GROUP BY a.time
由于您可以确信a.id只能是1个值,因此min将是该值。我很想知道是否有人有更好的解决方案,但我过去曾做过类似的事情来解决类似的问题
SELECT
a.time,
SUM(a.x)*(SELECT SUM(b.weight) FROM b WHERE b.id = MIN(a.id) AND b.time = a.time) AS z
FROM a
WHERE
a.id='FOO'
GROUP BY a.time
由于您可以确信a.id只能是1个值,因此最小值将是该值。尝试两个步骤:
;with cte as
(
SELECT
a.time,
SUM(a.x) AS z
FROM a
WHERE
a.id='FOO'
GROUP BY a.time
)
select a.time
,a.z*(SELECT SUM(b.weight) FROM b WHERE b.id = a.id AND b.time = a.time) as z
from cte a
尝试两个步骤:
;with cte as
(
SELECT
a.time,
SUM(a.x) AS z
FROM a
WHERE
a.id='FOO'
GROUP BY a.time
)
select a.time
,a.z*(SELECT SUM(b.weight) FROM b WHERE b.id = a.id AND b.time = a.time) as z
from cte a
你似乎已经知道原因了。你解释得很好。如果不知道应用程序的限制,很难回答。你能从多大程度上更改查询?a.id='FOO'只保证返回一条记录,如果该字段上有唯一的索引。但我不确定在标准SQL规则下,编译器是否有义务ed检查where子句中的某个字段是否有这样一个唯一的约束,以便删除将其包含在GROUP BY中的要求。我怀疑没有!为什么MSSQL认为内部查询可以为多个
a.id
生成结果,即使外部查询将a.id
限制为单个值?我认为is将是一个非常狭隘的优化,需要投入时间,对外部查询进行基数分析,作为内部查询编译的一部分,以允许免于遵守一般规则。@Jonathan Willcock:所以我的“为什么”问题的答案是:“因为SQL编译器还没有足够的智能来实现这一点”。很遗憾,但很清楚。您似乎已经知道了原因。您对此进行了完美的解释。在不了解应用程序的限制的情况下,很难回答。您可以对查询进行多大程度的更改?a.id='FOO'只保证返回一条记录,如果该字段上有唯一的索引。我不确定在标准SQL ru下les,编译器有义务检查where子句中的字段是否有这样一个唯一的约束,以便删除将其包含在GROUP BY中的要求。我怀疑没有!为什么MSSQL认为内部查询可以生成多个a.id
的结果,即使外部查询将a.id
限制为一个单一的值?我认为这将是一个非常狭窄的优化,需要投入时间,对外部查询进行基数分析,作为内部查询编译的一部分,以免除一般规则的约束。@Jonathan Willcock:所以我的“为什么”问题的答案是:“因为SQL编译器还不够聪明。”很遗憾,但很清楚。我也想到了这个解决方案,但担心MIN(a.id)
可能在a.id='Foo'
限制之前得到评估。数据库中有多个a.id
值。查询的选择部分在所有其他部分之后运行,因此在取最小值之前会过滤a.id。我也想到了这个解决方案,但担心min(a.id)
可能在a.id='Foo'
限制之前进行计算。数据库中有多个a.id
值。查询的选择部分在所有其他部分之后运行,因此在获取最小值之前将过滤a.id。