如何规范分组列的大写?
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
只是定义分组后的输出顺序 - 它仍然给出 a
和 A
.
那么:是否有一种理智的方法可以让所有分组的大写至少保持一致? (我将在另一天留下单独运行的一致性问题)
所需的输出,或者:
day name count
----------- ---- -----------
1 A 2
2 A 2
或:
day name count
----------- ---- -----------
1 a 2
2 a 2
编辑:没有 在组间一致时破坏大写。所以没有upper/lower。因此,如果其中一组始终具有值 BcDeF
,我希望该行的结果为 BcDeF
,而不是 bcdef
或 BCDEF
。
使用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;
在 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
只是定义分组后的输出顺序 - 它仍然给出 a
和 A
.
那么:是否有一种理智的方法可以让所有分组的大写至少保持一致? (我将在另一天留下单独运行的一致性问题)
所需的输出,或者:
day name count
----------- ---- -----------
1 A 2
2 A 2
或:
day name count
----------- ---- -----------
1 a 2
2 a 2
编辑:没有 在组间一致时破坏大写。所以没有upper/lower。因此,如果其中一组始终具有值 BcDeF
,我希望该行的结果为 BcDeF
,而不是 bcdef
或 BCDEF
。
使用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;