2011-07-05 15 views
20

Giả sử tôi có bảng này [Table1]Làm thế nào để nối tất cả các chuỗi từ một cột nhất định đối với từng nhóm

Name Mark 
------- ------ 
ABC  10 
DEF  10 
GHI  10 
JKL  20 
MNO  20 
PQR  30 

gì nên câu lệnh SQL của tôi để lấy một kỷ lục mà trông như thế này: (nhóm bởi [ dấu]). Tôi đã làm các cột 1 và 2 nhưng không biết làm thế nào để đạt được cột thứ ba (concat [name] với cùng [dấu])

mark count  names 
---- -----  ----------- 
10  3  ABC,DEF,GHI 
20  2  JKL,MNO 
30  1  PQR 

Tôi đang sử dụng Microsoft SQL. Xin vui lòng giúp đỡ. Cảm ơn

+0

Bạn đang sử dụng DBMS nào? –

+0

Microsoft SQL. Xin lỗi vì không bao gồm thông tin này – yonan2236

+0

Xem thêm http://stackoverflow.com/questions/451415/simulating-group-concat-mysql-function-in-ms-sql-server-2005 –

Trả lời

35

Nếu MS SQL 2005 trở lên.

declare @t table([name] varchar(max), mark int) 

insert @t values ('ABC', 10), ('DEF', 10), ('GHI', 10), 
    ('JKL', 20), ('MNO', 20), ('PQR', 30) 


select t.mark, COUNT(*) [count] 
    ,STUFF((
     select ',' + [name] 
     from @t t1 
     where t1.mark = t.mark 
     for xml path(''), type 
    ).value('.', 'varchar(max)'), 1, 1, '') [values] 
from @t t 
group by t.mark 

Output:

mark  count  values 
----------- ----------- -------------- 
10   3   ABC,DEF,GHI 
20   2   JKL,MNO 
30   1   PQR 
+1

+1 cho đường dẫn xml ('') – Pankaj

+0

Không tạo sự khác biệt khi không viết [giá trị]? – Pankaj

+0

@SQL, nó chỉ là bí danh, vì vậy không có vấn đề –

1

polishchuks giải pháp là tao nhã hơn, nhưng điều này về cơ bản là giống nhau, chúng ta chỉ cần đối phó với Dấu phẩy sau cùng khác nhau.

CREATE TABLE #Marks(Name nchar(3), Mark int) 

INSERT INTO #Marks 

SELECT 'ABC', 10 UNION ALL 
SELECT 'DEF', 10 UNION ALL 
SELECT 'GHI', 10 UNION ALL 
SELECT 'JKL', 20 UNION ALL 
SELECT 'MNO', 20 UNION ALL 
SELECT 'PQR', 30 


SELECT 
    mark, 
    [count], 
    CASE WHEN Len(Names) > 0 THEN LEFT(Names, LEN(Names) -1) ELSE '' END names 
    FROM 
(
SELECT 
    Mark, 
    COUNT(Mark) AS [count], 
     (
     SELECT DISTINCT 
      Name + ', ' 
     FROM 
      #Marks M1 
     WHERE M1.Mark = M2.Mark 
     FOR XML PATH('')  
     ) Names 
FROM #Marks M2 
GROUP BY Mark 
) M 
+0

Tôi không chắc liệu bạn có cần mệnh đề khác biệt đầu tiên trong truy vấn con đầu tiên khi bạn đang làm theo từng nhóm, vui lòng sửa tôi nếu tôi sai ... – Ram

+0

bạn sẽ không cần đến nó – woggles

4

Đây là câu trả lời liên quan đến hiệu suất!

http://jerrytech.blogspot.com/2010/04/tsql-concatenate-strings-1-2-3-and.html

Sử dụng chức năng XML trong truy vấn lớn là kẻ giết hiệu suất.

Sử dụng CTE là một siêu sao hiệu suất.

Kiểm tra liên kết, nó sẽ giải thích cách thực hiện.

Tôi thừa nhận công việc để thực hiện nó nhiều hơn.

Nhưng kết quả là mili giây trên hàng triệu hàng.

0

Dựa trên Itzik Ben-Gan, Bên trong Microsoft SQL Server 2005: Lập trình T-SQL, tr. 215:

IF OBJECT_ID('dbo.Table1') IS NOT NULL 
    DROP TABLE dbo.Table1 ; 
GO 
CREATE TABLE dbo.Table1 (Name VARCHAR(10), Mark INT) ; 

INSERT INTO dbo.Table1 (Name, Mark) VALUES ('ABC',  10) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('DEF',  10) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('GHI',  10) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('JKL',  20) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('MNO',  20) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('PQR',  30) ; 


WITH DelimitedNames AS 
(
    SELECT Mark, T2.Count, 
     ( SELECT Name + ',' AS [text()] 
      FROM dbo.Table1 AS T1 
      WHERE T1.Mark = T2.Mark 
      ORDER BY T1.Mark 
      FOR XML PATH('')) AS Names 
    FROM (SELECT Mark, COUNT(*) AS Count FROM dbo.Table1 GROUP BY Mark) AS T2 
) 
SELECT Mark, Count, LEFT(Names, LEN(NAMES) - 1) AS Names 
FROM DelimitedNames ;