Come usare COALESCE con più righe e senza virgola precedente?


27

Sto cercando di ottenere quanto segue:

California | Los Angeles, San Francisco, Sacramento
Florida    | Jacksonville, Miami

Purtroppo sto ricevendo ", Los Angeles, San Francisco, Sacramento, Jacksonville, Miami"

Posso ottenere i risultati desiderati usando la funzione STUFF, ma mi chiedevo se esiste un modo più pulito di farlo usando COALESCE?

STATE       | CITY
California  | San Francisco
California  | Los Angeles
California  | Sacramento
Florida     | Miami
Florida     | Jacksonville 


DECLARE @col NVARCHAR(MAX);
SELECT @col= COALESCE(@col, '') + ',' + city
FROM tbl where city = 'California';
SELECT @col;

Grazie

Risposte:


45

Questo potrebbe essere l'approccio più pulito che stai cercando. Fondamentalmente, controlla se la variabile è stata ancora inizializzata. In caso contrario, impostalo sulla stringa vuota e aggiungi la prima città (senza virgola iniziale). In tal caso, aggiungi una virgola, quindi aggiungi la città.

DECLARE @col nvarchar(MAX);
SELECT @col = COALESCE(@col + ',', '') + city
  FROM dbo.tbl WHERE state = 'California';

Naturalmente, questo funziona solo per il popolamento di una variabile per stato. Se stai tirando la lista per ogni stato uno alla volta, c'è una soluzione migliore in un colpo solo:

SELECT [state], cities = STUFF((
    SELECT N', ' + city FROM dbo.tbl
    WHERE [state] = x.[state]
    FOR XML PATH(''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tbl AS x
GROUP BY [state]
ORDER BY [state];

risultati:

state       cities
----------  --------------------------------------
California  San Francisco, Los Angeles, Sacramento  
Florida     Miami, Jacksonville

Per ordinare in base al nome della città all'interno di ogni stato:

SELECT [state], cities = STUFF((
    SELECT N', ' + city FROM dbo.tbl
    WHERE [state] = x.[state]
    ORDER BY city
    FOR XML PATH(''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tbl AS x
GROUP BY [state]
ORDER BY [state];

Nel database SQL di Azure o in SQL Server 2017+, è possibile usare la nuova STRING_AGG()funzione :

SELECT [state], cities = STRING_AGG(city, N', ')
  FROM dbo.tbl
  GROUP BY [state]
  ORDER BY [state];

E ordinato per nome della città:

SELECT [state], cities = STRING_AGG(city, N', ') 
                         WITHIN GROUP (ORDER BY city)
  FROM dbo.tbl
  GROUP BY [state]
  ORDER BY [state];

Grazie Aaron. La mia soluzione attuale è quasi identica alla tua tranne che sto usando DISTINCT invece di GROUP BY.
user2732180

2
@ user2732180 È necessario utilizzare GROUP BY in quanto è più probabile che esegua la concatenazione una volta per stato. Con DISTINCT applicherà la stessa concatenazione per ogni istanza della California, per esempio, e solo allora butterà via tutto il lavoro che ha fatto generando quei duplicati.
Aaron Bertrand

6

Solo per aggiungere alla risposta di Aaron sopra ...

Tenere presente che è ORDER BYpossibile interrompere includendo solo l'ultimo elemento nella query. Nel mio caso, non stavo raggruppando, quindi non sono sicuro che questo faccia la differenza. Sto usando SQL 2014. Nel mio caso, ho qualcosa come value1, value2, value3 ... ma il mio risultato nella variabile era solo value3.


Aaron ha commentato per dire:

Questo è stato segnalato almeno quattro volte su Connect:

  1. In Concatenazione di variabili e ordina per filtri risultati (come dove condizione)
  2. (n) la creazione di varchar da ResultSet non riesce quando viene aggiunto ORDER BY
  3. L'assegnazione di una variabile locale da un SELECT ordinato con CROSS APPLYs e una funzione con valori di tabella restituisce solo l'ultimo valore
  4. Quando si concatenano i valori varchar (max) / nvarchar (max) da una variabile di tabella, è possibile che vengano restituiti risultati errati se si filtra e si ordina da una colonna non primaria

Risposta di esempio da Microsoft:

Il comportamento che stai vedendo è in base alla progettazione. L'uso delle operazioni di assegnazione (concatenazione in questo esempio) nelle query con la clausola ORDER BY ha un comportamento indefinito.

La risposta fa riferimento anche a KB 287515:

PRB: il piano di esecuzione e i risultati delle query di concatenazione aggregate dipendono dalla posizione dell'espressione

La soluzione è usare FOR XML PATH(il secondo approccio nella risposta di Aaron) se l'ordine di concatenazione è importante e, naturalmente, se si desidera essere sicuri di includere tutti i valori. Vedi anche:

nvarchar concatenazione / indice / nvarchar (max) comportamento inspiegabile su StackTranslate.it

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.