Ghép Nối Nhiều Bản Ghi Vào Một Dòng

Vũ Huy Tâm

Ví dụ bạn có bảng:
ProductID CustomerName
---------- -------------
1          Tuấn
1          Minh
1          Linh
2          Ngọc
2          Hiền

Bạn muốn kết quả ra như sau:
ProductID CustomerName
---------- -------------
1          Tuấn, Minh, Linh
2          Ngọc, Hiền

Bạn có thể dùng câu lệnh này:

SELECT DISTINCT C2.ProductID, 
    SUBSTRING(
        (
            SELECT ','+C1.CustomerName  AS [TEXT()]
            FROM dbo.Customer C1
            WHERE C1.ProductID = C2.ProductID
            ORDER BY C1.ProductID
            FOR XML PATH ('')
        ), 2, 1000) CustomerList
FROM dbo.Customer C2

Trường hợp bạn không cần group by ProductID mà chỉ cần một danh sách khách hàng nối với nhau, bạn có thể dùng câu lệnh đơn giản hơn sau:

DECLARE @NAMES NVARCHAR(4000) 
SELECT @NAMES = COALESCE(@NAMES + ', ', '') + CustomerName 
FROM dbo.Customer
SELECT @NAMES



17 Comments
Posted on 18/12/2014 | Categories: SQL Server Programming, Tip & Trick

Các bài viết tương tự

Comments
  • lamgak (18/12/2014 11:17 pm)

    Hi all!

    Mọi người có thể tham khảo thêm ở link.
    https://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/

    Theo kinh nghiệm của mình. Đối với bảng nhỏ và chỉ lần list ra 1 cột -> query Tab(Customer) 2 lần thì dùng cách trên ok.
    Nếu cần format cho nhiều cột thì nên dùng cursor và update vào temp table. “The Cursor approach”.

    good luck!

  • tuan le (22/12/2014 12:03 am)

    Bac Vu Huy Tam oi. Bac co dang o ha noi ko? Minh nho tu van cho he thong database tren cty minh duoc khong? So dt cua minh 0984452189

  • Quan tran (09/01/2015 2:55 am)

    Có một cách nữa , dùng STUFF:

    SELECT ProductID ,
    STUFF((SELECT ‘, ‘ + CustomerName
    FROM Customer C1
    WHERE C1.ProductID = C2.ProductID
    FOR XML PATH(”)),1,1,”) as CustomerList
    FROM Customer C2
    GROUP BY ProductID

  • Snake_IT302 (25/05/2015 2:07 am)

    Ngoài ra có thể sử dụng hàm concat.
    vd: in oracle
    select ProductID, wm_concat(CustomerName) as CustomerName
    from Customer
    group by ProductID order by ProductID

  • question&anwer (06/07/2015 9:58 pm)

    Các cách trên chỉ nên sử dung nếu dữ lieu bang là nhỏ. còn khoảng 2000 dòng là chậm lắm.

  • LÊ MINH TRUNG (15/09/2015 6:22 am)

    Các bác giúp mình với:
    Mình có các table như sau:
    - BANLE(KHOA,LOC,SOBILL, MAKHO, NGAY, SOLUONGTONG, SOTIENTONG, NGAY TAO, NGAYXOA, NGUOITAO, NGUOIXOA)
    - BANLE_CHITIET(KHOA,LOC,KHOACHITIET,MAVATTU,SOLUONG,DONGIA,SOTIEN)
    - DANHMUC_KHO(MAKHO,TENKHO,MACONGTY)

    Mình muốn lọc ra các bill đã hủy trong tháng 8/2015 của công ty A theo định dạng sau:
    – SOBILL SOLUONGTONG SOTIENTONG
    1. MAVATTU SOLUONG SOTIEN NGAYXOA
    2. MAVATTU SOLUONG SOTIEN NGAYXOA

    CÂU LỆNH SQL MÌNH NHƯ SAU

    SELECT SOBILL,SUM(B.SOLUONG) AS SOLUONG,SUM(B.SOTIEN) AS SOTIEN,
    	SUBSTRING
    	(
     
    	) 
    FROM BANLE A, BANLE_CT B, DM_KHO C
    WHERE 
    	MONTH(NGAY)=8 AND YEAR(NGAY)=2015
    	AND NGAYXOA IS NOT NULL
    	AND A.KHOA=B.KHOA
    	AND A.LOC=B.LOC
    	AND A.MAKHO=C.MAKHO AND C.MACTY='10'
    GROUP BY SOBILL

    CÁC BÁC GIÚP EM VỚI. TKS.

  • phạm duy an (23/10/2015 9:27 pm)

    bác Tâm cho em hỏi trong trường hợp trường ‘ CustomerName’ em thay bằng một trường khác có kiểu là số (numeric) thì câu lệnh sẽ viết như thế nào ạ, cám ơn bácnhieeuff.

  • thanh (23/01/2016 7:10 am)

    Các cao thủ giúp em với ,em không biết post vào đâu nhờ các anh chỉ giúp em , em có bài toán nghĩ mãi ko ra
    dự liệu của em

    Nickname StatusWin
    Hung Thắng
    Hung Thắng
    Hung Thắng
    Đại Thắng
    Đại Thắng
    Hung Thắng
    Hung Thua
    Hung Thắng
    Hung Thắng
    Đại Thua
    Đại Thua
    Đại Thắng
    Đại Thắng
    Đại Thắng

    em muốn lấy dữ liệu theo kiểu sắp sếp từ cao đến thấp theo tài khoản có số trận thắng liên tiếp

    như dự liệu ở trên

    Hùng có 4 trận thắng liên tiếp
    Đại có 3 trận thắng liên tiếp

    Mong mọi người giúm em với ,em nghĩ mã ko ra được , không lam xong bài toán này ko biết có được thưởng tết nữa hay không

    • Yugiking0 (02/02/2016 12:21 am)

      Bạn thử cái này xem được không ?

      DECLARE @Nickname VARCHAR(8), @StatusWin VARCHAR(300)
      DECLARE @oNickname VARCHAR(8)='', @oStatusWin VARCHAR(300)=''
      DECLARE @i INT=1
      SELECT Nickname, StatusWin,99 AS zcount INTO #kq FROM ketqua WHERE 1=0
       
      DECLARE cr CURSOR FOR SELECT Nickname, StatusWin FROM ketqua
      OPEN cr
      FETCH NEXT FROM cr INTO @Nickname, @StatusWin
      WHILE @@FETCH_STATUS = 0
      BEGIN
      	IF (@oNickname=@Nickname AND @oStatusWin=@StatusWin)
      		BEGIN
      			SET @i=1+@i
      		END
      	ELSE
      		BEGIN
      			INSERT INTO #kq VALUES(@oNickname,@oStatusWin,@i)
      			SET @i=1
      		END	
      	PRINT @i
      	SELECT @oNickname=@Nickname,@oStatusWin=@StatusWin
      	FETCH NEXT FROM cr INTO @Nickname, @StatusWin
      END
      CLOSE cr
      DEALLOCATE cr
      DELETE #kq WHERE Nickname=''
      SELECT CASE Nickname WHEN 'D' THEN N'Đại' WHEN 'H' THEN N'Hùng' END AS Ten,
      CASE StatusWin WHEN 0 THEN N'Thua' WHEN 1 THEN N'Thắng' END AS Trang_thai,
      zcount AS lien_tuc
      FROM #kq ORDER BY Trang_thai,zcount DESC
      DROP TABLE #kq
    • Luân (22/02/2016 8:53 am)

      #1
      Theo mình hiểu ý bạn là :
      (1) nhóm các tài khoản có số trận thắng liên tiếp
      (2) sort nhóm phía trên lại

      -> (1) mình sẽ nhóm các dòng liên tiếp có trạng thái (thắng, thua) trên cùng user lại
      select tba.*, id – row_number() over (order by name, id) –g/s id la PK
      from tba
      -> (2) sort
      dựa vào (1) để xử lý, cái này chắc ko khó

      Ban search với keyword này nhé: count consecutive rows

      Mình đang suy nghĩ thêm cách #2 .

  • Yugiking0 (02/02/2016 12:22 am)
    CREATE TABLE ketqua(
    	[MATCH] INT NULL,
    	[Nickname] CHAR(8) NOT NULL,
    	[Name] NVARCHAR(300) NULL,
    	[StatusWin] BIT NULL
    )
    GO
     
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(1, N'H', N'Hung', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(2, N'D', N'Hung', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(3, N'H', N'Hung', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(4, N'D', N'Đại', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(5, N'D', N'Đại', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(6, N'H', N'Hung', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(7, N'H', N'Hung', 0)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(8, N'H', N'Hung', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(9, N'H', N'Hung', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(10, N'D', N'Đại', 0)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(11, N'D', N'Đại', 0)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(12, N'D', N'Đại', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(13, N'D', N'Đại', 1)
    INSERT INTO ketqua(MATCH, Nickname, Name, StatusWin) VALUES(14, N'D', N'Đại', 1)
  • Dương Nguyễn (16/02/2016 12:52 am)

    Chào anh!
    Em xin hỏi cách giải quyết thuật toán như sau:
    Em viết một procedure truyền từ ngày(1/2/2016) -> đến ngày(4/2/2016), kết quả trả ra là:
    KhachHang NgayMua
    A 1/2/2016
    A 2/2/2016
    A 4/2/2016
    Em muốn xử lý dữ liệu này để ra 1 bảng kết quả theo ý mình là:

    KhachHang N1/2/16 N2/2/16 N3/2/2016 N4/2/2016
    A 1 1 0 1

    Bạn nào giúp mình dc ko? Số cột tùy vào thời gian truyền vào nhé.
    Thanks.

  • Phong (18/08/2016 12:11 am)

    ProductID CustomerName
    ———- ————-
    1 Tuấn
    1 Minh
    1 Linh
    2 Ngọc
    2 Hiền

    Mình muốn kết quả ra như sau: thì phải làm sao ạ, rất mong giúp đở.
    ProductID CustomerName Name2 Name3
    ———- ————-
    1 Tuấn Minh Linh
    2 Ngọc Hiền

  • Phong (18/08/2016 12:13 am)

    ProductID CustomerName
    ———- ————-
    1 Tuấn
    1 Minh
    1 Linh
    2 Ngọc
    2 Hiền

    Mình muốn kết quả ra như sau: thì phải làm sao ạ, rất mong giúp đở.
    ProductID —— CustomerName ——CotName2 —–CotName3
    ———- ————-
    1 —————-Tuấn —————–Minh————— Linh
    2————— Ngọc —————–Hiền

    • Phong (23/08/2016 5:07 am)

      Đang chờ hướng dẫn dể hiển thị theo từng cột ạ,

      Regards,
      Phong

  • Thúy (27/10/2016 4:56 am)

    các bạn ơi mình có bài toán này, giúp mình viết stored produce
    Dữ liệu có Dữ liệu cần cộng dồn
    100 100
    500 600 (500+100)
    400 1000 (500+100+400)

    Mình muốn lấy dữ liệu cộng dồn. Hình như là đệ quy, bạn nào có code share mình với
    Cảm ơn nhiều

  • Thúy (27/10/2016 4:57 am)

    các bạn ơi mình có bài toán này, giúp mình viết stored produce
    Dữ liệu có—– Dữ liệu cần cộng dồn
    100———— 100
    500 ————-600 (500+100)
    400 ————-1000 (500+100+400)

    Mình muốn lấy dữ liệu cộng dồn. Hình như là đệ quy, bạn nào có code share mình với
    Cảm ơn nhiều

Leave a Reply

Hướng dẫn: Để nhập mã T-SQL bạn dùng thẻ <pre lang="tsql"> và </pre>.
Ví dụ: <pre lang="tsql">SELECT * FROM MyTable</pre>