Làm cách nào để sử dụng COALESCE với nhiều hàng và không có dấu phẩy trước?


27

Tôi đang cố gắng để đạt được những điều sau đây:

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

Thật không may, tôi đang nhận được ", Los Angeles, San Francisco, Sacramento, Jacksonville, Miami"

Tôi có thể đạt được kết quả mong muốn của mình bằng chức năng STUFF, nhưng tự hỏi liệu có cách nào thực hiện sạch hơn bằng cách sử dụng COALESCE không?

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;

Cảm ơn

Câu trả lời:


45

Đây có thể là cách tiếp cận sạch hơn bạn sau. Về cơ bản, kiểm tra xem biến đã được khởi tạo chưa. Nếu không, đặt chuỗi đó vào chuỗi trống và nối thêm thành phố đầu tiên (không có dấu phẩy hàng đầu). Nếu có, hãy thêm dấu phẩy, sau đó nối thành phố.

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

Tất nhiên, điều đó chỉ hoạt động để điền một biến cho mỗi trạng thái. Nếu bạn đang kéo danh sách cho từng trạng thái một lần, có một giải pháp tốt hơn trong một lần chụp:

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

Các kết quả:

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

Để đặt hàng theo tên thành phố trong mỗi tiểu bang:

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

Trong Azure SQL Database hoặc SQL Server 2017+, bạn có thể sử dụng chức năng mớiSTRING_AGG() :

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

Và đặt hàng theo tên thành phố:

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

Cảm ơn Aaron. Giải pháp hiện tại của tôi gần giống với giải pháp của bạn ngoại trừ tôi đang sử dụng DISTINCT thay vì NHÓM THEO.
dùng2732180

2
@ user2732180 Bạn nên sử dụng NHÓM THEO vì có nhiều khả năng thực hiện ghép nối một lần cho mỗi trạng thái. Ví dụ, với DISTINCT, nó sẽ áp dụng cách ghép tương tự cho mọi trường hợp của California, và chỉ sau đó vứt bỏ tất cả công việc mà nó đã tạo ra các bản sao đó.
Aaron Bertrand

6

Chỉ cần thêm vào câu trả lời của Aaron ở trên ...

Xin lưu ý rằng ORDER BYcó thể phá vỡ chỉ bằng cách bao gồm mục cuối cùng trong truy vấn của bạn. Trong trường hợp của tôi, tôi đã không nhóm, vì vậy không chắc điều đó có làm nên sự khác biệt không. Tôi đang sử dụng SQL 2014. Trong trường hợp của tôi, tôi có một cái gì đó như value1, value2, value3 ... nhưng kết quả của tôi trong biến chỉ là value3.


Aaron bình luận để nói:

Điều này đã được báo cáo ít nhất bốn lần trên Connect:

  1. Kết hợp biến và sắp xếp theo thứ tự các kết quả của bộ lọc (như điều kiện)
  2. (n) xây dựng varchar từ result Set không thành công khi ORDER BY được thêm vào
  3. Chỉ định một biến cục bộ từ một CHỌN có thứ tự với các ứng dụng CROSS và hàm có giá trị bảng chỉ trả về giá trị cuối cùng
  4. Khi nối các giá trị varchar (max) / nvarchar (max) từ một biến bảng, kết quả không chính xác có thể được trả về nếu lọc và sắp xếp theo cột không phải là khóa chính

Ví dụ phản hồi từ Microsoft:

Hành vi bạn đang thấy là do thiết kế. Sử dụng các thao tác gán (ghép trong ví dụ này) trong các truy vấn với mệnh đề ORDER BY có hành vi không xác định.

Phản hồi cũng tham khảo KB 287515:

PRB: Kế hoạch thực hiện và kết quả của các truy vấn tổng hợp phụ thuộc vào vị trí biểu hiện

Giải pháp là sử dụng FOR XML PATH(cách tiếp cận thứ hai trong câu trả lời của Aaron) nếu thứ tự ghép là quan trọng và tất nhiên, nếu bạn muốn chắc chắn bao gồm tất cả các giá trị. Cũng thấy:

nvarchar concatenation / index / nvarchar (max) hành vi không thể giải thích được trên Stack Overflow

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.