sql-server 在T-SQL中,Group by是区分大小写的,即使数据库和服务器排序规则是CI

k2arahey  于 2022-10-31  发布在  其他
关注(0)|答案(5)|浏览(108)

我还没有找到任何文档来解释以下行为,数据库和服务器级排序都是CI(不区分大小写),为什么在这方面它仍然区分大小写?

--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

第二个查询会传回这个错误消息。
消息8120,级别16,状态1,第2行
数据行'a.name'在选取清单中无效,因为它未包含在汇总函数或GROUP BY子句中。

mftmpeh8

mftmpeh81#

这更多的是引申的议论,真实的回答。
我认为此问题是由于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将SELECTGROUP BY子句中的CASE语句都转换为表达式时,它会得到不同的表达式值。在这种情况下,您最好在select中执行'bertrand',在group by子句中执行'charlie',因为如果CASE表达式不是100% select和group by子句之间的匹配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()函数中 Package 了不同的大小写字符串,SQL Server仍然无法处理它。

neskvpey

neskvpey2#

问题在于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

而“亚当”和“伯特兰”的情况是一样的。

z4bn682m

z4bn682m3#

你发现了一些真正奇怪的东西,但我认为问题在于你在groupby语句中使用了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

分组依据应该应用于整个表而不是单个行。我可能缺少这样做的一些原因,但我认为按值进行有条件分组是没有意义的。
我更惊讶的是,第一个查询能用,而不是第二个查询不能用。比较'a' = 'A'与比较一列和另一列有细微的不同。SQL Server在检查列是否在group by中时似乎不使用排序规则设置。您从第二个查询收到的错误消息是:'select中的此列与group by中的列不相同'而不是'这些值不相等'。

sxpgvts3

sxpgvts34#

这不是一个答案,而是一个评论,它需要比评论部分提供的更多的空间和功能。
如果根本问题是要最大限度地降低在查询中犯此类错误的风险,因为必须在GROUP BY和SELECT中维护复杂的表达式,那么您可以首先使用CROSS APPLY来避免重复。

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;

这种方式的最后查询不太优雅,但可以获得相同的结果:表达式只定义一次。

pxyaymoc

pxyaymoc5#

定义不起作用
在你的第二个我得到一个语法错误
消息8120,级别16,状态1,第1行列'a.name'在选择列表中无效,因为它既未包含在聚合函数中,也未包含在GROUP BY子句中。
此时,它甚至还没有尝试处理查询
为什么你坚持语法错误是因为CI不被尊重
这是语法错误-不是执行错误
select必须与组匹配
因此,出于某种原因,SQL解析器需要匹配大小写
重要的是它如何处理查询
如果您有区分大小写的表,您是否希望TSQL要求区分大小写的列名和表名?
这对我的工作
adam的和为6它同时支持小写(a)和大写(A)
这说明此group by 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

相关问题