我有以下查询:
WITH cteCountryLanguageMapping AS (
SELECT * FROM (
VALUES
('Spain', 'English'),
('Spain', 'Spanish'),
('Sweden', 'English'),
('Switzerland', 'English'),
('Switzerland', 'French'),
('Switzerland', 'German'),
('Switzerland', 'Italian')
) x ([Country], [Language])
)
SELECT
[Country],
CASE COUNT([Language])
WHEN 1 THEN MAX([Language])
WHEN 2 THEN STRING_AGG([Language], ' and ')
ELSE STRING_AGG([Language], ', ')
END AS [Languages],
COUNT([Language]) AS [LanguageCount]
FROM cteCountryLanguageMapping
GROUP BY [Country]
我希望瑞士的“语言”列中的值以逗号分隔,即:
| Country | Languages | LanguageCount
--+-------------+-------------------------------------------+--------------
1 | Spain | Spanish and English | 2
2 | Sweden | English | 1
3 | Switzerland | French, German, Italian, English | 4
相反,我得到以下输出(这4个值用and
分隔):
| Country | Languages | LanguageCount
--+-------------+-------------------------------------------+--------------
1 | Spain | Spanish and English | 2
2 | Sweden | English | 1
3 | Switzerland | French and German and Italian and English | 4
我想念什么?
这里是另一个示例:
SELECT y, STRING_AGG(z, '+') AS STRING_AGG_PLUS, STRING_AGG(z, '-') AS STRING_AGG_MINUS
FROM (
VALUES
(1, 'a'),
(1, 'b')
) x (y, z)
GROUP by y
| y | STRING_AGG_PLUS | STRING_AGG_MINUS
--+---+-----------------+-----------------
1 | 1 | a+b | a+b
这是SQL Server中的错误吗?
答案 0 :(得分:15)
是的,这是一个Bug(tm),存在于(截至编写时)SQL Server 2017 CU12之前的版本中(但根据@DanGuzman的说法,没有出现在Azure SQL数据库中,因此显然它已得到修复,并且该修复程序可能降落在下一个CU中)。具体而言,只要STRING_AGG(x, <separator>)
匹配,优化器中执行公共子表达式消除(确保我们不会计算超出必要量的表达式)的部分会不正确地认为x
形式的所有表达式都是相同的<separator>
是什么,并将它们与查询中第一个计算出的表达式统一起来。
一种解决方法是通过对x
进行某种(近)身份转换来确保不匹配。由于我们正在处理字符串,因此串联一个空字符串可以做到:
SELECT y, STRING_AGG(z, '+') AS STRING_AGG_PLUS, STRING_AGG('' + z, '-') AS STRING_AGG_MINUS
FROM (
VALUES
(1, 'a'),
(1, 'b')
) x (y, z)
GROUP by y
答案 1 :(得分:0)
不要重复自己*。您正在通过使用MAX(...)
,LIST_AGG(...', ')
和LIST_AGG(...' and ')
来重复自己。您可以像这样简单地重写查询,并可能得到更好的计划:
WITH cteCountryLanguageMapping AS (
SELECT * FROM (
VALUES
('Spain', 'English'),
('Spain', 'Spanish'),
('Sweden', 'English'),
('Switzerland', 'English'),
('Switzerland', 'French'),
('Switzerland', 'German'),
('Switzerland', 'Italian')
) x (Country, Language)
), results AS (
SELECT
Country,
COUNT(Language) AS LanguageCount,
STRING_AGG(Language, ', ') AS Languages
FROM cteCountryLanguageMapping
GROUP BY Country
)
SELECT Country, LanguageCount, CASE LanguageCount
WHEN 2 THEN REPLACE(Languages, ', ', ' and ')
ELSE Languages
END AS Languages_Fixed
FROM results
结果:
| Country | LanguageCount | Languages_Fixed |
|-------------|---------------|----------------------------------|
| Spain | 2 | Spanish and English |
| Sweden | 1 | English |
| Switzerland | 4 | French, German, Italian, English |
*我也不想通过说这是一个错误来重复别人。