하위 쿼리의 여러 결과를 단일 쉼표로 구분 된 값으로 결합


84

두 개의 테이블이 있습니다.

TableA
------
ID,
Name

TableB
------
ID,
SomeColumn,
TableA_ID (FK for TableA)

관계는 하나 개의 행 TableA의 많은 - TableB.

이제 다음과 같은 결과를보고 싶습니다.

ID     Name      SomeColumn

1.     ABC       X, Y, Z (these are three different rows)
2.     MNO       R, S

이것은 작동하지 않습니다 (여러 결과가 하위 쿼리에 있음).

SELECT ID,
       Name, 
       (SELECT SomeColumn FROM TableB WHERE F_ID=TableA.ID)
FROM TableA

클라이언트 측에서 처리하면 사소한 문제입니다. 그러나 이것은 모든 페이지에서 X 쿼리를 실행해야 함을 의미합니다. 여기서 X는의 결과 수입니다 TableA.

의 행에 대해 여러 결과를 반환하므로 단순히 GROUP BY 또는 이와 유사한 작업을 수행 할 수 없습니다 TableA.

COALESCE 또는 이와 유사한 것을 활용하는 UDF가 작동하는지 확실하지 않습니까?

답변:


134

이것조차도 목적을 달성 할 것입니다

샘플 데이터

declare @t table(id int, name varchar(20),somecolumn varchar(MAX))
insert into @t
    select 1,'ABC','X' union all
    select 1,'ABC','Y' union all
    select 1,'ABC','Z' union all
    select 2,'MNO','R' union all
    select 2,'MNO','S'

질문:

SELECT ID,Name,
    STUFF((SELECT ',' + CAST(T2.SomeColumn AS VARCHAR(MAX))
     FROM @T T2 WHERE T1.id = T2.id AND T1.name = T2.name
     FOR XML PATH('')),1,1,'') SOMECOLUMN
FROM @T T1
GROUP BY id,Name

산출:

ID  Name    SomeColumn
1   ABC     X,Y,Z
2   MNO     R,S

13
사용자 기능을 요구하지 않고 문제를 해결하기 때문에 이것이 왜 선택되지 않았는지 확실하지 않습니다. 여기에 표현 된 것과 동일한 아이디어를 볼 수 있습니다. codecorner.galanter.net/2009/06/25/… 이 답변보다 앞선 것이므로 "원본"일 수 있습니다
Paul D' Ambra

1
이 더 높은 평가가 없습니다 확실하지 왜, 여기에 같은
마르셀

1
안녕하세요 priyanka, "and t1.name = t2.name"절이 필요한지, 왜 필요한지 말씀해 주시겠습니까?
Koen

2
이것은 훌륭합니다. 내 서버를 죽이는 허용 된 답변에 나열된 UDF 기능을 최적화하려고했습니다. 102 초 검색에서 1 미만으로 줄었습니다. 실행 계획 비교는 78 % -22 % 였지만 실행 시간과는 관련이 없습니다 ...
toxaq

선행 ''이 필요하다는 점을 상기 시키십시오. 그렇지 않으면 출력에서 ​​꺾쇠 괄호로 끝날 것입니다.
Tim Scarborough

45

1. UDF를 만듭니다.

CREATE FUNCTION CombineValues
(
    @FK_ID INT -- The foreign key from TableA which is used 
               -- to fetch corresponding records
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @SomeColumnList VARCHAR(8000);

SELECT @SomeColumnList =
    COALESCE(@SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20)) 
FROM TableB C
WHERE C.FK_ID = @FK_ID;

RETURN 
(
    SELECT @SomeColumnList
)
END

2. 하위 쿼리에서 사용 :

SELECT ID, Name, dbo.CombineValues(FK_ID) FROM TableA

3. 저장 프로 시저를 사용하는 경우 다음과 같이 할 수 있습니다.

CREATE PROCEDURE GetCombinedValues
 @FK_ID int
As
BEGIN
DECLARE @SomeColumnList VARCHAR(800)
SELECT @SomeColumnList =
    COALESCE(@SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20)) 
FROM TableB
WHERE FK_ID = @FK_ID 

Select *, @SomeColumnList as SelectedIds
    FROM 
        TableA
    WHERE 
        FK_ID = @FK_ID 
END

1
이것은 여전히 ​​해킹처럼 느껴집니다. 나는 여전히 하위 쿼리를 사용하고 있으므로 여전히 많은 추가 처리가 진행되고 있습니다. 더 나은 솔루션이 존재한다고 확신합니다 (테이블 구조 조정 또는 문제를 보는 다른 방법).
Donnie Thomas

1
나는 이것을 해킹이라고 부르지 않을 것입니다. 커서보다 효율적이며 원하는 방식으로 구조화 된 데이터로 임시 테이블을 만드는 데 필요한 오버 헤드가 없습니다.
Scott Lawrence

1
열은 매개 변수가 될 수 없습니다. 현재로서는 모든 자녀 관계를위한 기능을 만들어야합니다!
John Paul Jones

1
괜찮습니다.이 특정 열만 결합하면됩니다. 나머지는 '전통적인'조인입니다.
Donnie Thomas

이 방법없이이 작업을 수행하는 가장 좋은 방법은 기억 나지 않습니다.
aF.

11

나는 당신이 COALESCE와 올바른 길을 가고 있다고 생각합니다. 쉼표로 구분 된 문자열을 작성하는 예는 여기를 참조하십시오.

http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string


2
대박! COALESCE를 논의하는 링크를 보았지만 트리거를 사용하여 UDF를 만드는 것과 관련이 있습니다. 제출 한 링크에는 단일 SELECT 문이있는 키가 있습니다. 다른 사람들이 더 쉽게 찾을 수 있도록 올바른 솔루션으로 답변을 추가하고 있습니다. 감사!
Donnie Thomas

1
안녕하세요 Ben, 답변에는 UDF를 만드는 방법 등과 같은 좀 더 자세한 정보가 필요하다고 생각합니다.이 문제를 파악하면 솔루션을 커뮤니티 편집 가능한 답변으로 추가하겠습니다. 자유롭게 편집 해 주시면 답변으로 받아 들일 것입니다. 혼란을 드려 죄송합니다.
Donnie Thomas

11

MySQL에는 요청한 것을 반환 하는 group_concat 함수가 있습니다.

SELECT TableA.ID, TableA.Name, group_concat(TableB.SomeColumn) 
as SomColumnGroup FROM TableA LEFT JOIN TableB ON 
TableB.TableA_ID = TableA.ID

1
SQL Server에 비슷한 기능이 있다면 완벽했을 것입니다. 현재로서는 Ben의 솔루션을 사용하여 원하는 것을 함께 망치고 있습니다.
Donnie Thomas

0

보다 정확한 응답을 위해 더 자세한 정보를 제공해야 할 수도 있습니다.

데이터 세트가 좁아 보이므로 결과 당 행을 사용하고 클라이언트에서 후 처리를 수행하는 것을 고려할 수 있습니다.

따라서 서버를 실제로 만들고 싶다면 작업이 다음과 같은 결과 집합을 반환합니다.

ID       Name       SomeColumn
1        ABC        X
1        ABC        Y
1        ABC        Z
2        MNO        R
2        MNO        S

물론 간단한 INNER JOIN on ID

결과 집합을 클라이언트에 다시 가져 오면 CurrentName이라는 변수를 유지하고 원하는 유용한 작업에 SomeColumn 수집을 중지 할 때 트리거로 사용합니다.


나는 이것을 생각했지만 이것이 우아한 해결책인지는 잘 모르겠습니다. SQL Server가 제대로 구성된 결과 집합을 반환하도록하고 싶습니다. 추가 처리가 필요한 것은 아닙니다. 추가 정보가 필요하십니까? 테이블 구조를 단순화했지만 이해하신 것 같습니다.
Donnie Thomas

0

테이블 A에 WHERE 절만 있다고 가정하면 다음과 같이 저장 프로 시저를 만듭니다.

SELECT Id, Name From tableA WHERE ...

SELECT tableA.Id AS ParentId, Somecolumn 
FROM tableA INNER JOIN tableB on TableA.Id = TableB.F_Id 
WHERE ...

그런 다음 DataSet ds를 채 웁니다. 그때

ds.Relations.Add("foo", ds.Tables[0].Columns("Id"), ds.Tables[1].Columns("ParentId"));

마지막으로 모든 줄에 쉼표를 넣는 반복 레이아웃을 페이지에 추가 할 수 있습니다.

 <asp:DataList ID="Subcategories" DataKeyField="ParentCatId" 
DataSource='<%# Container.DataItem.CreateChildView("foo") %>' RepeatColumns="1"
 RepeatDirection="Horizontal" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="top" 
runat="server" >

이런 식으로 클라이언트 측에서 수행하지만 하나의 쿼리로 데이터베이스와 프런트 엔드간에 최소한의 데이터를 전달합니다.


0

나는 priyanka.sarkar가 언급 한 솔루션을 시도했지만 OP가 요청 한대로 작동하지 않았습니다. 내가 끝내게 된 해결책은 다음과 같습니다.

SELECT ID, 
        SUBSTRING((
            SELECT ',' + T2.SomeColumn
            FROM  @T T2 
            WHERE WHERE T1.id = T2.id
            FOR XML PATH('')), 2, 1000000)
    FROM @T T1
GROUP BY ID

-1

아래 해결책 :

SELECT GROUP_CONCAT(field_attr_best_weekday_value)as RAVI
FROM content_field_attr_best_weekday LEFT JOIN content_type_attraction
    on content_field_attr_best_weekday.nid = content_type_attraction.nid
GROUP BY content_field_attr_best_weekday.nid

이것을 사용하면 조인을 변경할 수도 있습니다.


-1
SELECT t.ID, 
       t.NAME, 
       (SELECT t1.SOMECOLUMN 
        FROM   TABLEB t1 
        WHERE  t1.F_ID = T.TABLEA.ID) 
FROM   TABLEA t; 

이것은 하위 쿼리를 사용하여 다른 테이블에서 선택하는 데 작동합니다.


-1

모든 답변을 검토했습니다. 나는 데이터베이스 삽입에서 다음과 같아야한다고 생각합니다.

ID     Name      SomeColumn
1.     ABC       ,X,Y Z (these are three different rows)
2.     MNO       ,R,S

쉼표는 이전 끝에 있어야하며 다음과 같이 검색해야합니다. %,X,%

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.