在配置为不区分大小写的SQL Server上,当group by
列不是第一个[n][var]char
列时,group by
可能会产生有趣的结果。本质上,它看起来像遇到“第一”的任何行(其中“第一”在没有顺序的情况下都是未定义的):赢得该分组。例如:
select x.[day], x.[name], count(1) as [count]
from (
select 1 as [day], 'a' as [name]
union all select 1, 'A'
union all select 2, 'A'
union all select 2, 'a'
) x group by x.[day], x.[name]
对于我来说,这返回:
day name count
----------- ---- -----------
1 A 2
2 a 2
由于已发生分组,因此使用
min(x.[name])
无效。我不能在
order by
之前添加group by
,因为这是非法的;并在order by
之后添加group by
只是在分组后定义了输出顺序-它仍然提供a
和A
。因此:是否有一种明智的方法可以使所有分组的大写字母至少保持一致? (我将离开另一天的问题是单独运行的一致性)
所需的输出,可以是:
day name count
----------- ---- -----------
1 A 2
2 A 2
或者:
day name count
----------- ---- -----------
1 a 2
2 a 2
编辑:,而组之间保持一致时,不破坏大小写。因此没有上限/下限。因此,如果其中一个组的值始终为
BcDeF
,则我希望该行的结果为BcDeF
,而不是bcdef
或BCDEF
。
最佳答案
我将为此使用开窗功能。通过使用ROW_NUMBER
并使用不区分大小写的排序规则进行分区,但是按区分大小写的排序规则进行排序,我们将选择一个与原始大小写一致的结果,但是它将对它们进行分组,就像它们是相同的一样:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY [day], [name]
ORDER BY [name] COLLATE SQL_Latin1_General_Cp1_Cs_AS),
N = COUNT(*) OVER(PARTITION BY [day], [name])
FROM ( select 1 as [day], 'a' as [name]
union all select 1, 'A'
union all select 2, 'A'
union all select 2, 'a'
union all select 3, 'BcDeF'
union all select 3, 'bCdEf') X
)
SELECT *
FROM CTE
WHERE RN = 1;
它返回:
╔═════╦═══════╦════╦═══╗
║ day ║ name ║ RN ║ N ║
╠═════╬═══════╬════╬═══╣
║ 1 ║ A ║ 1 ║ 2 ║
║ 2 ║ A ║ 1 ║ 2 ║
║ 3 ║ BcDeF ║ 1 ║ 2 ║
╚═════╩═══════╩════╩═══╝
遵循@AndriyM的评论,如果要在整个结果集中使用相同的大写字母,而不是仅在同一天使用,请使用:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY [day], [name]
ORDER BY [name] COLLATE SQL_Latin1_General_Cp1_Cs_AS),
N = COUNT(*) OVER(PARTITION BY [day], [name])
FROM ( select 1 as [day], 'a' as [name]
union all select 1, 'A'
union all select 2, 'A'
union all select 2, 'a'
union all select 3, 'BcDeF'
union all select 3, 'bCdEf') X
)
SELECT [day],
MAX([name] COLLATE SQL_Latin1_General_Cp1_CS_AS) OVER (PARTITION BY [name]) [name],
N
FROM CTE
WHERE RN = 1;
关于sql - 如何规范分组依据列的大小写?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39637389/