我没有找到任何解释以下行为的文档,db和服务器级别排序规则都是CI(Case Insensitive),为什么它在这方面仍然区分大小写?
--Works
SELECT CASE name WHEN 'a' THEN 'adam' ELSE 'bertrand' END AS name, COUNT(value) FROM
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'b',1
UNION
SELECT 'b',2
)a
GROUP BY CASE name WHEN 'a' THEN 'adam' ELSE 'bertrand' END
--Returns an Error Message, please note the "B" in Bertrand in the GROUP BY
SELECT CASE name WHEN 'a' THEN 'adam' ELSE 'bertrand' END name, COUNT(value) FROM
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'b',1
UNION
SELECT 'b',2
)a
GROUP BY CASE name WHEN 'a' THEN 'adam' ELSE 'Bertrand' END
第二个查询返回此错误消息。
Msg 8120,Level 16,State 1,Line 2
专栏' a.name'在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。
答案 0 :(得分:5)
这更多是对真实答案的延伸评论。
我认为这个问题来自SQL Server如何尝试评估case
语句表达式。
要证明服务器具有案例意义,您可以运行以下两个语句
SELECT CASE WHEN 'Bertrand' = 'bertrand' THEN 'true' ELSE 'false' end
-
DECLARE @base TABLE
(NAME VARCHAR(1)
,value INT
)
INSERT INTO @base Values('a',0),('b',0),('B',0)
SELECT * FROM @base
SELECT name, COUNT(value) AS Cnt
FROM @base
GROUP BY NAME
结果:
正如你在这里看到的那样,即使第二行中的字母是小写,第三行中的字母是大写,group by子句也忽略了这种情况。查看执行计划,
有两个表达式Expr 1007 COUNT([value])
Expr 1004 CONVERT_IMPLICIT(int,[Expr1007],0)
现在我们将其更改为case
SELECT CASE WHEN name = 'a' THEN 'adam' ELSE 'bertrand' END AS name, COUNT(value) AS Cnt
FROM @base
GROUP BY CASE WHEN name = 'a' THEN 'adam' ELSE 'bertrand' END
执行计划显示3个表达式。 2从上面和新的
Expr 1004 CASE WHEN [NAME]='a' THEN 'adam' ELSE 'bertrand' END
所以此时聚合函数不再评估列name
的值,而是现在它评估表达式的值。
我认为发生的事情可能是不正确的。当SQL Server将CASE
和SELECT
子句中的GROUP BY
语句转换为表达式时,它会提供不同的表达式值。在这种情况下,您也可以在'bertrand'
和select
中'charlie'
进行操作
在group by
子句中,因为如果CASE
表达式在select和group by子句之间不是100%匹配,SQL Server会将它们视为不再匹配的不同Expr
aka(列)。
更新
为了更进一步,以下陈述也将失败。
SELECT CASE WHEN name = 'a' THEN 'adam' ELSE UPPER('bertrand') END AS name
,COUNT(value) AS Cnt
FROM @base
GROUP BY CASE WHEN name = 'a' THEN 'adam' ELSE UPPER('Bertrand') END
即使在UPPER()
函数中包装不同的case字符串,SQL Server仍然无法处理它。
答案 1 :(得分:0)
当select和group by中的语句应该相同时会出现问题,但您可以按如下方式编写查询
select name, count(value) from
(
SELECT CASE name WHEN 'a' THEN 'adam' ELSE 'bertrand' END name, value FROM
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'b',1
UNION
SELECT 'b',2
)a
)t
GROUP BY name
这不是关于案例敏感性的,请看一下这个样本
This works
SELECT CASE name WHEN 'a' THEN 'adam' when 'b' then 'bertrand' end name, COUNT(value) FROM
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'b',1
UNION
SELECT 'b',2
)a
GROUP BY CASE name WHEN 'a' THEN 'adam' when 'b' then 'bertrand' END
This does not work
SELECT CASE name when 'b' then 'bertrand' WHEN 'a' THEN 'adam' end name, COUNT(value) FROM
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'b',1
UNION
SELECT 'b',2
)a
GROUP BY CASE name WHEN 'a' THEN 'adam' when 'b' then 'bertrand' END
虽然'adam'和'bertrand'的情况相同。
答案 2 :(得分:0)
你发现了一些非常奇怪的东西,但我认为问题在于你在group by语句中完全使用case语句。它应该是:
SELECT CASE name WHEN 'a' THEN 'adam' ELSE 'bertrand' END AS name FROM
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'b',1
UNION
SELECT 'b',2
) a
GROUP BY name
group by应该应用于整个表而不是单个行。我可能错过了这样做的一些理由,但我认为有条件地按值分组是有道理的。
我更感到惊讶的是,第一个起作用,而第二个起作用。比较' a' =' A'与将列与另一列进行比较略有不同。 SQL服务器似乎没有使用此检查中的排序规则设置来查看列是否在组中。您从第二个查询中收到的错误消息是,'此列中的此列与组中的列不同于'而不是“这些价值观不相等”。
答案 3 :(得分:0)
定义是否有效 在你的第二个我得到语法错误
Msg 8120,Level 16,State 1,Line 1 Column' a.name'是无效的 选择列表,因为它不包含在聚合中 函数或GROUP BY子句。
此时它甚至没有尝试处理查询 为什么你坚持语法错误是因为CI不受尊重
这是语法错误 - 不是执行错误
选择必须与组匹配
因此,出于某种原因,SQL解析器需要匹配案例
重要的是它如何处理查询
如果你有区分大小写的表,你会期望TSQL需要区分大小写的列和表名吗?
这项工作对我来说 亚当总和为6 它尊重较低的(a)和大写(A)
这表明该组由IS不区分大小写 向下投票关心解释?
SELECT CASE a.name WHEN 'a' THEN 'adam' ELSE 'bertrand' END AS name, sum(value)
from
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'a',2
UNION
SELECT 'A',3
UNION
SELECT 'b',10
UNION
SELECT 'b',20
UNION
SELECT 'B',30
) as a
GROUP BY CASE name WHEN 'a' THEN 'adam' ELSE 'bertrand' END
并且这表示不区分大小写的
SELECT CASE a.name WHEN 'A' THEN 'adam' ELSE 'Bertrand' END AS name, sum(value)
from
(
SELECT 'a' AS name,1 AS value
UNION
SELECT 'a',2
UNION
SELECT 'A',3
UNION
SELECT 'b',10
UNION
SELECT 'b',20
UNION
SELECT 'B',30
) as a
GROUP BY CASE name WHEN 'A' THEN 'adam' ELSE 'Bertrand' END
答案 4 :(得分:0)
这不是一个答案,但是评论恰好需要比评论部分提供更多的空间和能力。
如果由于必须在GROUP BY和SELECT中维护一个复杂的表达式,最基本的问题是最大限度地降低在查询中出现这种错误的风险,那么你可以通过使用{{{}来避免重复。 3}}。而不是
SELECT SomeComplexExpression, SomeAggregation
FROM ...
GROUP BY SomeComplexExpression;
你可以做到
SELECT x.GroupingCriterion, SomeAggregation
FROM ...
CROSS APPLY (SELECT SomeComplexExpression AS GroupingCriterion) AS x
GROUP BY x.GroupingCriterion;
现在你需要在一个地方维护复杂的分组表达式。
希望您使用SQL Server 2005或更高版本才能使用此方法。否则,您始终可以使用派生表:
SELECT GroupingCriterion, SomeAggregation
FROM (
SELECT SomeComplexExpression AS GroupingCriterion, OtherData
FROM ...
) AS s
GROUP BY GroupingCriterion;
最终查询不那么优雅,但实现了相同的结果:表达式只定义了一次。