如何规范分组列的大写?

How can I normalize the capitalization of a group-by column?

在 SQL 配置为不区分大小写的服务器上,当 [n][var]char 列不是第一个 group by 列时,group by 会产生有趣的结果。本质上,它看起来像它遇到的任何行 "first" (其中 "first" 在没有订单的情况下未定义):赢得该分组。例如:

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]

哪个returns,对我来说:

day         name count
----------- ---- -----------
1           A    2
2           a    2

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

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

那么:是否有一种理智的方法可以让所有分组的大写至少保持一致? (我将在另一天留下单独运行的一致性问题)

所需的输出,或者:

day         name count
----------- ---- -----------
1           A    2
2           A    2

或:

day         name count
----------- ---- -----------
1           a    2
2           a    2

编辑:没有 在组间一致时破坏大写。所以没有upper/lower。因此,如果其中一组始终具有值 BcDeF,我希望该行的结果为 BcDeF,而不是 bcdefBCDEF

使用upper()lower():

select x.[day], lower(x.[name]) as 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];

你是正确的 SQL 服务器从不确定的行中选择一个值。 min()max() 没有帮助,因为它们的值是等价的。最简单的解决方案是明确选择您想要的大小写。

您可以在 GROUP BY 子句中使用 UPPER 将所有值转换为相同的大小写。

Group by 中使用不区分大小写的排序规则,例如:

select day, name, count(*)
from tablename
group by day, name collate SQL_Latin1_General_Cp1_CI_AS_KI_WI

可能SQL服务器这里有问题?使用另一个 dbms,它执行为:

SQL>create table t (d int, name varchar(10));
SQL>insert into t values (1,'A');
SQL>insert into t values (2,'A');
SQL>insert into t values (2,'a');
SQL>insert into t values (3,'BcDeF');
SQL>insert into t values (3,'bCdEf');
SQL>insert into t values (4,'a');
SQL>select d, name, count(*)
SQL&from t
SQL&group by d, name collate english_1;
          d name
=========== ========== ====================
          1 A                             1
          2 A                             2
          3 BcDeF                         2
          4 a                             1

                  4 rows found

其中 english_1 是不区分大小写的排序规则。

如预期?

我会为此使用窗口函数。通过使用 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;

它returns:

╔═════╦═══════╦════╦═══╗
║ 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;