Bagaimana cara menggunakan COALESCE dengan banyak baris dan tanpa koma sebelumnya?

27

Saya mencoba mencapai yang berikut:

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

Sayangnya, saya mendapatkan ", Los Angeles, San Francisco, Sacramento, Jacksonville, Miami"

Saya dapat mencapai hasil yang saya inginkan menggunakan fungsi STUFF, tetapi bertanya-tanya apakah ada cara yang lebih bersih untuk melakukannya menggunakan 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;

Terima kasih

pengguna2732180
sumber

Jawaban:

45

Ini mungkin pendekatan bersih yang Anda cari. Pada dasarnya, periksa apakah variabel sudah diinisialisasi. Jika belum, setel ke string kosong, dan tambahkan kota pertama (tanpa koma terkemuka). Jika sudah, maka tambahkan koma, lalu tambahkan kota.

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

Tentu saja, itu hanya berfungsi untuk mengisi variabel per negara. Jika Anda menarik daftar untuk setiap negara bagian satu per satu, ada solusi yang lebih baik dalam satu kesempatan:

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];

Hasil:

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

Untuk memesan berdasarkan nama kota di setiap negara bagian:

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];

Di Azure SQL Database atau SQL Server 2017+, Anda dapat menggunakan fungsi baruSTRING_AGG() :

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

Dan dipesan dengan nama kota:

SELECT [state], cities = STRING_AGG(city, N', ') 
                         WITHIN GROUP (ORDER BY city)
  FROM dbo.tbl
  GROUP BY [state]
  ORDER BY [state];
Aaron Bertrand
sumber
Terima kasih Aaron. Solusi saya saat ini hampir identik dengan milik Anda kecuali saya menggunakan DISTINCT bukan GROUP BY.
user2732180
2
@ user2732180 Anda harus menggunakan GROUP BY karena lebih mungkin untuk melakukan penggabungan satu kali per negara. Dengan DISTINCT ia akan menerapkan Rangkaian yang sama untuk setiap instance California, misalnya, dan hanya kemudian membuang semua pekerjaan yang dilakukannya menghasilkan duplikat tersebut.
Aaron Bertrand
6

Hanya untuk menambah jawaban Harun di atas ...

Sadarilah bahwa sebuah ORDER BYbreak hanya dapat menyertakan item terakhir dalam kueri Anda. Dalam kasus saya, saya tidak mengelompokkan, jadi tidak yakin apakah itu membuat perbedaan. Saya menggunakan SQL 2014. Dalam kasus saya, saya memiliki sesuatu seperti value1, value2, value3 ... tetapi hasil saya dalam variabel hanya value3.


Aaron berkomentar untuk mengatakan:

Ini telah dilaporkan setidaknya empat kali di Connect:

  1. Dalam Rangkaian variabel dan pesanan berdasarkan hasil filter (seperti kondisi di mana)
  2. (n) pembangunan varchar dari ResultSet gagal ketika ORDER BY ditambahkan
  3. Menetapkan variabel lokal dari SELECT yang dipesan dengan CROSS APPLYs dan fungsi bernilai tabel hanya mengembalikan nilai terakhir
  4. Saat menggabungkan nilai varchar (max) / nvarchar (max) dari variabel tabel, hasil yang salah dapat dikembalikan jika memfilter dan memesan dengan kolom non-primary-key

Contoh respons dari Microsoft:

Perilaku yang Anda lihat adalah dengan desain. Menggunakan operasi penugasan (gabungan dalam contoh ini) dalam kueri dengan klausa ORDER BY telah menentukan perilaku.

Respons itu juga merujuk KB 287515:

PRB: Rencana Eksekusi dan Hasil Permintaan Gabungan Agregat Tergantung Lokasi Ekspresi

Solusinya adalah menggunakan FOR XML PATH(pendekatan kedua dalam jawaban Harun) jika urutan rangkaian itu penting dan, tentu saja, jika Anda ingin memastikan untuk memasukkan semua nilai. Lihat juga:

nvarchar concatenation / index / nvarchar (max) perilaku yang tidak bisa dijelaskan pada Stack Overflow

ebol2000
sumber