Mar*_*ell 6 sql sql-server group-by case-sensitive case-insensitive
在配置为不区分大小写的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]
Run Code Online (Sandbox Code Playgroud)
哪个回来,对我来说:
day name count
----------- ---- -----------
1 A 2
2 a 2
Run Code Online (Sandbox Code Playgroud)
使用min(x.[name])没有效果,因为分组已经发生.
我不能添加order by 之前的group by,因为这是非法的; 并添加order by 后的group by只是定义了分组后的输出顺序-它仍然给a和A.
所以:有没有一种理智的方式来实现这一点,资本化至少对所有分组都是一致的?(我将在另一天离开单独运行的问题)
期望的输出,或者:
day name count
----------- ---- -----------
1 A 2
2 A 2
Run Code Online (Sandbox Code Playgroud)
要么:
day name count
----------- ---- -----------
1 a 2
2 a 2
Run Code Online (Sandbox Code Playgroud)
编辑:在组之间保持一致时不破坏大小写.所以没有上/下.因此,如果其中一个组始终具有该值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;
Run Code Online (Sandbox Code Playgroud)
它返回:
????????????????????????
? day ? name ? RN ? N ?
????????????????????????
? 1 ? A ? 1 ? 2 ?
? 2 ? A ? 1 ? 2 ?
? 3 ? BcDeF ? 1 ? 2 ?
????????????????????????
Run Code Online (Sandbox Code Playgroud)
按照@ 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;
Run Code Online (Sandbox Code Playgroud)