sql - 如何规范分组依据列的大小写?

标签 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]

对于我来说,这返回:
day         name count
----------- ---- -----------
1           A    2
2           a    2

由于已发生分组,因此使用min(x.[name])无效。

我不能在order by之前添加group by,因为这是非法的;并在order by之后添加group by只是在分组后定义了输出顺序-它仍然提供aA

因此:是否有一种明智的方法可以使所有分组的大写字母至少保持一致? (我将离开另一天的问题是单独运行的一致性)

所需的输出,可以是:
day         name count
----------- ---- -----------
1           A    2
2           A    2

或者:
day         name count
----------- ---- -----------
1           a    2
2           a    2

编辑:,而组之间保持一致时,不破坏大小写。因此没有上限/下限。因此,如果其中一个组的值始终为BcDeF,则我希望该行的结果为BcDeF,而不是bcdefBCDEF

最佳答案

我将为此使用开窗功能。通过使用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/

相关文章:

php - 无法使用 PHP 从 SQL Server 存储过程检索输出参数

.net - 是否可以反编译 SQL Server CLR 存储过程程序集?

mysql - SQL 组结果为一行

sql - 从具有复合主键的另一个表插入或更新表

mysql - 安装 mysql2 gem

sql - 为什么 'Select' 被称为 DML 语句?

python - 使用多索引条件选择数据帧的子集

mysql - 使用 where 和语句在 1 列中搜索

c# - 如何在单个事务中将文件写入磁盘并插入数据库记录?

MySQL 分组与求和