为什么列序号对ORDER BY
合法,但对GROUP BY
不合法?也就是说,任何人都可以告诉我为什么这个查询
SELECT OrgUnitID, COUNT(*) FROM Employee AS e GROUP BY OrgUnitID
不能写为
SELECT OrgUnitID, COUNT(*) FROM Employee AS e GROUP BY 1
编写像
这样的查询是完全合法的SELECT OrgUnitID FROM Employee AS e ORDER BY 1
我真的想知道关系微积分是否存在一些微妙的东西,这会阻止分组正常工作。
问题是,我的例子非常简单。通常我想要分组的列实际上是一个计算,并且必须在GROUP BY中重复完全相同的计算是(a)烦人和(b)更有可能在维护期间产生错误。这是一个简单的例子:
SELECT DATEPART(YEAR,LastSeenOn), COUNT(*)
FROM Employee AS e
GROUP BY DATEPART(YEAR,LastSeenOn)
我认为SQL的规范化规则只能在数据库中表示一次 data ,也应该扩展到代码。我只想对该计算表达式进行一次修改(在SELECT
列列表中),并且能够在GROUP BY
中按顺序引用它。
澄清:我是专门研究SQL Server 2008的,但我想知道总体答案。
答案 0 :(得分:8)
其中一个原因是因为ORDER BY是SQL Query中运行的最后一件事,这是操作的顺序
因此,一旦获得SELECT子句中的列,就可以使用序数定位
EDIT,根据评论补充说明 以此为例
create table test (a int, b int)
insert test values(1,2)
go
下面的查询将解析没有问题,它将无法运行
select a as b, b as a
from test
order by 6
这是错误
Msg 108,Level 16,State 1,Line 3
ORDER BY位置编号6超出了选择列表中项目数的范围。
这也解析好
select a as b, b as a
from test
group by 1
但它出现了这个错误
Msg 164,Level 15,State 1,Line 3
每个GROUP BY表达式必须至少包含一个不是外部引用的列。
答案 1 :(得分:3)
SQL中存在许多基本的不一致性,使用标量就是其中之一。例如,任何人都可能期望
select * from countries
order by 1
和
select * from countries
order by 1.00001
是一个类似的查询(毕竟两者之间的差异可以无限小),但事实并非如此。
答案 2 :(得分:1)
使用别名:
SELECT DATEPART(YEAR,LastSeenOn) as 'seen_year', COUNT(*) as 'count'
FROM Employee AS e
GROUP BY 'seen_year'
** 编辑 **
如果您不允许GROUP BY alias
,则此处为解决方案/解决方法:
SELECT seen_year
, COUNT(*) AS Total
FROM (
SELECT DATEPART(YEAR,LastSeenOn) as seen_year, *
FROM Employee AS e
) AS inline_view
GROUP
BY seen_year
答案 3 :(得分:1)
我不确定标准是否指定它是否有效,但我认为它是依赖于实现的。我刚用一个SQL引擎尝试了你的第一个例子,它工作得很好。