COALESCE, çoklu satırlarla ve virgüllerden önce nasıl kullanılır?


27

Aşağıdakileri başarmaya çalışıyorum:

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

Ne yazık ki, "Los Angeles, San Francisco, Sacramento, Jacksonville, Miami" alıyorum

İstenilen sonuçları STUFF işlevini kullanarak elde edebilirim, ancak COALESCE kullanarak daha temiz bir yol olup olmadığını merak ediyordum?

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;

Teşekkürler

Yanıtlar:


45

Bu peşinde olduğunuz daha temiz bir yaklaşım olabilir. Temel olarak, değişkenin henüz başlatılıp başlatılmadığını kontrol edin. Değilse, boş dizgeye ayarlayın ve ilk şehri ekleyin (virgül yok). Varsa, virgül ekleyin, sonra şehri ekleyin.

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

Tabii ki, bu sadece durum başına bir değişkeni doldurmak için işe yarar. Listeyi her bir durum için birer birer çekiyorsanız, bir kerede daha iyi bir çözüm var:

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

Sonuçlar:

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

Her eyalette şehir adına göre sipariş etmek için:

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

Azure SQL Veritabanı veya SQL Server 2017+ 'de, yeni STRING_AGG()işlevi kullanabilirsiniz :

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

Ve şehir adına göre sıralı:

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

Sağol Aaron. Şu anki çözümüm, GROUP BY yerine DISTINCT kullanıyorum dışında sizinkilerle aynı.
user2732180

2
@ user2732180 Bir birleştirmeyi her durum için bir kez gerçekleştirme olasılığı daha yüksek olduğundan, bir GROUP BY kullanmalısınız. DISTINCT ile, örneğin, her California örneği için aynı birleştirmeyi uygular ve ancak o kopyaları ürettiği tüm işleri atır.
Aaron Bertrand

6

Sadece Aaron'un cevabına yukarıdakileri eklemek için ...

Bir ORDER BYsorgunun yalnızca son öğeyi dahil ederek kırılabileceğini unutmayın. Benim durumumda gruplama yapmadım, bu yüzden bunun bir fark yaratıp yaratmadığından emin değilim. SQL 2014 kullanıyorum. Benim durumumda değer1, değer2, değer3 gibi bir şeyim var ... ancak değişkendeki sonucum yalnızca değer3 idi.


Aaron şöyle dedi:

Bu, Connect’te en az dört kez bildirildi:

  1. Değişken bitiştirme ve süzgeç sonuçlarına göre sırala (koşul gibi)
  2. (n) ORDER BY eklendiğinde ResultSet'ten gelen varchar oluşturma işlemi başarısız oluyor
  3. CROSS APPLY ile sipariş edilen bir SELECT'ten bir yerel değişken atama ve tablo değerli bir işlev yalnızca son değeri döndürür
  4. Bir tablo değişkeninden varchar (max) / nvarchar (max) değerlerini birleştirirken, birincil olmayan bir sütuna göre filtreleme ve sipariş verirken yanlış sonuçlar alınabilir

Microsoft'tan örnek yanıt:

Gördüğünüz davranış tasarım gereğidir. ORDER BY deyimiyle yapılan sorgularda atama işlemlerini (bu örnekte birleştirme) kullanmak tanımsız davranışa sahiptir.

Bu yanıt ayrıca KB 287515’e de başvuruyor:

SORUN: İfade Planı ve İfade Konumuna Bağlı Toplam Birleştirme Sorgularının Sonuçları

Çözüm, FOR XML PATHbirleştirme sırasının önemli olup olmadığını ve tabii ki tüm değerleri içerdiğinden emin olmak istiyorsanız (Aaron'un cevabındaki ikinci yaklaşım) kullanmaktır. Ayrıca bakınız:

nvarchar birleştirme / dizin / nvarchar (maks) Yığın Taşması üzerine açıklanamaz davranış

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.