it-swarm.com.de

STRING_AGG verhält sich nicht wie erwartet

Ich habe folgende Frage:

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]

Ich habe erwartet, dass der Wert in der Spalte Languages ​​für die Schweiz durch Kommas getrennt wird, d. H .:

  | Country     | Languages                                 | LanguageCount
--+-------------+-------------------------------------------+--------------
1 | Spain       | Spanish and English                       | 2
2 | Sweden      | English                                   | 1
3 | Switzerland | French, German, Italian, English          | 4

Stattdessen bekomme ich die folgende Ausgabe (die 4 Werte werden durch and getrennt):

  | Country     | Languages                                 | LanguageCount
--+-------------+-------------------------------------------+--------------
1 | Spain       | Spanish and English                       | 2
2 | Sweden      | English                                   | 1
3 | Switzerland | French and German and Italian and English | 4

Was vermisse ich?


Hier ist ein anderes Beispiel:

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

Ist das ein Fehler in SQL Server?

14
Tom Hunter

Ja, dies ist ein Fehler (tm), der in (zum Zeitpunkt des Schreibens) Versionen bis zu SQL Server 2017 CU12 (jedoch nicht gemäß @DanGuzman in der Azure SQL-Datenbank vorhanden ist), so dass er anscheinend bereits behoben wurde und der Fix in der nächste CU). Insbesondere der Teil des Optimierers, der die Beseitigung allgemeiner Teilausdrücke durchführt (wobei sichergestellt wird, dass Ausdrücke nicht mehr als notwendig berechnet werden), betrachtet alle Ausdrücke des Formulars STRING_AGG(x, <separator>) falsch als identisch, solange x übereinstimmt, unabhängig davon, was <separator> ist Der erste berechnete Ausdruck in der Abfrage.

Eine Problemumgehung besteht darin, sicherzustellen, dass x nicht übereinstimmt, indem eine Art (nahe) Identitätsumwandlung darauf ausgeführt wird. Da wir es mit Strings zu tun haben, wird das Verketten eines leeren Strings Folgendes tun:

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
15
Jeroen Mostert

Wiederholen Sie sich nicht *. Sie wiederholen sich mit MAX(...), LIST_AGG(...', ') und LIST_AGG(...' and '). Sie könnten Ihre Abfrage einfach so umschreiben und einen besseren Plan erhalten:

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

Ergebnis:

| Country     | LanguageCount | Languages_Fixed                  |
|-------------|---------------|----------------------------------|
| Spain       | 2             | Spanish and English              |
| Sweden      | 1             | English                          |
| Switzerland | 4             | French, German, Italian, English |

DB Fiddle

* Ich wollte nicht auch andere wiederholen, indem ich sagte, dass es sich um einen Fehler handelt.

0
Salman A