문제

을 고려한 데이터베이스에 테이블을 들고 이름으로 세 가지 행:

Peter
Paul
Mary

이 있는 쉬운 방법이 하나의의 문자열 Peter, Paul, Mary?

도움이 되었습니까?

해결책

는 경우에는 SQL Server2017 또는 Azure 참조하십시오 마티유 Renda 응답.

나는 유사한 문제를 하려고 할 때 두 가입 테이블로 일대다 관계입니다.에서 SQL2005 발견 XML PATH 방법을 처리할 수 있는 연결한의 행 매우 쉽습니다.

이 있는 경우 라는 테이블 STUDENTS

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

결과 내가 예상되었:

SubjectID       StudentName
----------      -------------
1               Mary, John, Sam
2               Alaina, Edward

내가 사용되는 다음 T-SQL:

SELECT Main.SubjectID,
       LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
    (
        SELECT DISTINCT ST2.SubjectID, 
            (
                SELECT ST1.StudentName + ',' AS [text()]
                FROM dbo.Students ST1
                WHERE ST1.SubjectID = ST2.SubjectID
                ORDER BY ST1.SubjectID
                FOR XML PATH ('')
            ) [Students]
        FROM dbo.Students ST2
    ) [Main]

당신 같은 일을 할 수 있습에서 더 콤팩트한 방법으로 할 수 있다면 concat 쉼표에서 처음 사용 substring 를 건너뛰기 처음 그래서 당신이 할 필요가 없 sub-쿼리:

SELECT DISTINCT ST2.SubjectID, 
    SUBSTRING(
        (
            SELECT ','+ST1.StudentName  AS [text()]
            FROM dbo.Students ST1
            WHERE ST1.SubjectID = ST2.SubjectID
            ORDER BY ST1.SubjectID
            FOR XML PATH ('')
        ), 2, 1000) [Students]
FROM dbo.Students ST2

다른 팁

이 답변은 돌아올 수 있습니다 예상치 못한 결과 일관된 결과를 얻으려면 다른 답변에 자세히 설명 된 XML 경로 메소드 중 하나를 사용하십시오.

사용 COALESCE:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name 
FROM People

몇 가지 설명 만 (이 답변은 비교적 규칙적인 견해를 얻는 것처럼 보이므로) :

  • Coalesce는 실제로 두 가지를 달성하는 유용한 속임수입니다.

1) 초기화 할 필요가 없습니다 @Names 빈 문자열 값으로.

2) 마지막에 추가 분리기를 벗을 필요가 없습니다.

  • 위의 솔루션은 행에 행에 잘못된 결과를 제공합니다. 없는 이름 값 (있는 경우 a 없는,, 없는 할 것 @Names 없는 그 행 후에는 다음 행이 다시 빈 문자열로 시작됩니다. 두 가지 솔루션 중 하나로 쉽게 고정됩니다.
DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL

또는:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + 
    ISNULL(Name, 'N/A')
FROM People

원하는 동작에 따라 (첫 번째 옵션 만 필터링 없는S OUT, 두 번째 옵션은 마커 메시지로 목록에 보관합니다.

하나의 방법은 아직 표시되지 않습니다 XML data() MS SQL Server의 명령은 다음과 같습니다.

fname이라는 열 하나의 열이있는 namelist라는 테이블을 가정합니다.

SELECT FName + ', ' AS 'data()' 
FROM NameList 
FOR XML PATH('')

보고:

"Peter, Paul, Mary, "

추가 쉼표 만 처리해야합니다.

편집하다: @nreilingh의 의견에서 채택 된대로 다음 방법을 사용하여 후행 쉼표를 제거 할 수 있습니다. 동일한 테이블 및 열 이름을 가정합니다.

STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands

SQL Server 2017+ 및 SQL Azure : String_agg

다음 버전의 SQL Server를 시작으로, 우리는 변수 또는 XML Witchery에 의지하지 않고도 행 전체를 연결할 수 있습니다.

string_agg (transact-sql)

그룹화없이

SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;

그룹화 :

SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;

그룹화 및 하위 분류

SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department 
GROUP BY GroupName;

~ 안에 SQL Server 2005

SELECT Stuff(
  (SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'')

SQL Server 2016에서

당신은 사용할 수 있습니다 JSON 구문의 경우

SELECT per.ID,
Emails = JSON_VALUE(
   REPLACE(
     (SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
    ,'"},{"_":"',', '),'$[0]._'
) 
FROM Person per

그리고 결과는 될 것입니다

Id  Emails
1   abc@gmail.com
2   NULL
3   def@gmail.com, xyz@gmail.com

데이터조차도 작동합니다. 귀하의 데이터에도 잘못된 XML 문자가 포함되어 있습니다.

그만큼 '"},{"_":"' 데이터가 포함되어 있으면 안전합니다 '"},{"_":"', 탈출 할 것입니다 "},{\"_\":\"

당신은 교체 할 수 있습니다 ', ' 모든 문자열 분리기와 함께


SQL Server 2017에서 Azure SQL 데이터베이스

새로운 것을 사용할 수 있습니다 String_agg 함수

MySQL에는 기능이 있습니다. group_concat (), 이를 통해 여러 행에서 값을 연결할 수 있습니다. 예시:

SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people 
FROM users 
WHERE id IN (1,2,3) 
GROUP BY a

사용 Coalesce - 여기에서 자세히 알아보십시오

예를 들어 :

102

103

104

그런 다음 SQL Server에 아래 코드를 작성하십시오.

Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers 
SELECT  @Numbers = COALESCE(@Numbers + ',', '') + Number
FROM   TableName where Number IS NOT NULL

SELECT @Numbers

출력은 다음과 같습니다.

102,103,104

포스트 그레 어레이는 굉장합니다. 예시:

일부 테스트 데이터 생성 :

postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE                                      
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');                                                          
INSERT 0 3
test=# select * from names;
 name  
-------
 Peter
 Paul
 Mary
(3 rows)

배열로 집계하십시오.

test=# select array_agg(name) from names;
 array_agg     
------------------- 
 {Peter,Paul,Mary}
(1 row)

배열을 쉼표로 구분 된 문자열로 변환합니다.

test=# select array_to_string(array_agg(name), ', ') from names;
 array_to_string
-------------------
 Peter, Paul, Mary
(1 row)

완료

Postgresql 9.0 이후입니다 훨씬 쉽습니다.

Oracle 11G Release 2는 ListAgg 함수를 지원합니다. 선적 서류 비치 여기.

COLUMN employees FORMAT A50

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.

경고

결과 문자열이 4000 문자 이상으로 이동할 가능성이있는 경우이 기능 구현에주의하십시오. 예외가 발생합니다. 이 경우 예외를 처리하거나 결합 된 문자열이 4000 문자 이상으로 이동하는 것을 방지하는 자신의 기능을 굴려야합니다.

SQL Server 2005 이상에서 아래 쿼리를 사용하여 행을 연결하십시오.

DECLARE @t table
(
    Id int,
    Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d' 

SELECT ID,
stuff(
(
    SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'') 
FROM (SELECT DISTINCT ID FROM @t ) t

집에서 SQL Server에 액세스 할 수 없으므로 여기 구문을 추측하지만 다소 적습니다.

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names

재귀 CTE 솔루션은 제안되었지만 코드는 제공되지 않았습니다. 아래 코드는 재귀 CTE의 예입니다. 결과가 질문과 일치하지만 데이터는 그렇지 않습니다. 상당히 주어진 설명과 일치하십시오. 테이블의 모든 행이 아니라 행 그룹 에서이 작업을 수행하고 싶다고 가정합니다. 테이블의 모든 행과 일치하도록 변경하는 것은 독자의 연습으로 남겨집니다.

;with basetable as 
(   SELECT id, CAST(name as varchar(max))name, 
        ROW_NUMBER() OVER(Partition By id     order by seq) rw, 
        COUNT(*) OVER (Partition By id) recs 
FROM (VALUES (1, 'Johnny', 1), (1,'M', 2), 
                  (2,'Bill', 1), (2, 'S.', 4), (2, 'Preston', 5), (2, 'Esq.', 6),
        (3, 'Ted', 1), (3,'Theodore', 2), (3,'Logan', 3),
                  (4, 'Peter', 1), (4,'Paul', 2), (4,'Mary', 3)

           )g(id, name, seq)
),
rCTE as (
    SELECT recs, id, name, rw from basetable where rw=1
    UNION ALL
    SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw+1
    FROM basetable b
         inner join rCTE r
    on b.id = r.id and b.rw = r.rw+1
)
SELECT name FROM rCTE
WHERE recs = rw and ID=4

최종 결과를 유지하고 그렇게 선택할 변수를 만들어야합니다.

가장 쉬운 솔루션

DECLARE @char VARCHAR(MAX);

SELECT @char = COALESCE(@char + ', ' + [column], [column]) 
FROM [table];

PRINT @char;

PostgreSQL 9.0부터 시작하는 것은 매우 간단합니다.

select string_agg(name, ',') 
from names;

9.0 이전 버전 array_agg() HGMNZ에서 표시된대로 사용할 수 있습니다

SQL Server vnext에서는 String_Agg 함수와 함께 내장됩니다. 자세한 내용은 여기를 참조하십시오.https://msdn.microsoft.com/en-us/library/mt790580.aspx

XML을 사용하면 쉼표로 행을 분리하는 데 도움이되었습니다. 추가 쉼표의 경우 SQL Server의 교체 기능을 사용할 수 있습니다. 쉼표를 추가하는 대신 AS 'data ()'를 사용하면 행을 공백과 연결하여 나중에 아래에 쓰여진 구문과 같이 쉼표로 대체 될 수 있습니다.

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 

추가 쉼표가없는 즉시 사용 가능한 솔루션 :

select substring(
        (select ', '+Name AS 'data()' from Names for xml path(''))
       ,3, 255) as "MyList"

빈 목록은 널 값을 초래합니다. 일반적으로 목록을 테이블 열 또는 프로그램 변수에 삽입합니다. 필요에 따라 255 최대 길이를 조정하십시오.

(Diwakar와 Jens Frandsen은 좋은 답변을 제공했지만 개선이 필요합니다.)

SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')

다음은 샘플입니다.

DECLARE @t TABLE (name VARCHAR(10))
INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
--Peter, Paul, Mary
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

이것은 처음에 길 잃은 쉼표를 넣습니다.

그러나 다른 열이 필요하거나 CSV에 하위 테이블이 필요한 경우 스칼라 사용자 정의 필드 (UDF)로 래핑해야합니다.

선택 조항에서 XML 경로를 상관 관계 서브 쿼리로 사용할 수 있습니다 (그러나 Google에서 일을하지 않기 때문에 다시 일할 때까지 기다려야합니다 :-).

다른 답변으로 답을 읽는 사람은 차량이나 학생과 같은 특정 도메인 테이블을 알고 있어야합니다. 솔루션을 테스트하기 위해 테이블을 생성하고 데이터로 채워야합니다.

아래는 SQL Server "Information_schema.columns"테이블을 사용하는 예입니다. 이 솔루션을 사용하면 테이블을 만들거나 데이터를 추가 할 필요가 없습니다. 이 예제는 데이터베이스의 모든 테이블에 대한 쉼표로 열 이름 목록을 만듭니다.

SELECT
    Table_Name
    ,STUFF((
        SELECT ',' + Column_Name
        FROM INFORMATION_SCHEMA.Columns Columns
        WHERE Tables.Table_Name = Columns.Table_Name
        ORDER BY Column_Name
        FOR XML PATH ('')), 1, 1, ''
    )Columns
FROM INFORMATION_SCHEMA.Columns Tables
GROUP BY TABLE_NAME 

Oracle DBS의 경우이 질문을 참조하십시오. 저장된 절차를 만들지 않고 여러 행을 오라클에서 어떻게 연결할 수 있습니까?

가장 좋은 답변은 @emmanuel이 Oracle 11G Release 2 이상에서 제공되는 내장 Listagg () 함수를 사용하는 것으로 보입니다.

SELECT question_id,
   LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id

@user762952가 지적한 것처럼 Oracle의 문서에 따르면 http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php, wm_concat () 함수도 옵션입니다. 안정적으로 보이지만 Oracle은 모든 응용 프로그램 SQL에 사용하는 것을 명시 적으로 권장하므로 자신의 위험에 따라 사용하십시오.

그 외에는 자신의 기능을 작성해야합니다. 위의 Oracle 문서에는이를 수행하는 방법에 대한 안내서가 있습니다.

나는 우아함을 정말 좋아했다 다나의 대답. 그냥 완성하고 싶었습니다.

DECLARE @names VARCHAR(MAX)
SET @names = ''

SELECT @names = @names + ', ' + Name FROM Names 

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)

널 값을 피하려면 concat ()를 사용할 수 있습니다.

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names

이 답변은 서버에서 작동하려면 약간의 권한이 필요합니다.

어셈블리 당신에게 좋은 옵션입니다. 그것을 만드는 방법을 설명하는 많은 사이트가 있습니다. 내가 잘 설명 된 것은 이것입니다. 하나

원한다면 이미 어셈블리를 만들었고 DLL을 다운로드 할 수 있습니다. 여기.

다운로드 한 후에는 SQL 서버에서 다음 스크립트를 실행해야합니다.

CREATE Assembly concat_assembly 
   AUTHORIZATION dbo 
   FROM '<PATH TO Concat.dll IN SERVER>' 
   WITH PERMISSION_SET = SAFE; 
GO 

CREATE AGGREGATE dbo.concat ( 

    @Value NVARCHAR(MAX) 
  , @Delimiter NVARCHAR(4000) 

) RETURNS NVARCHAR(MAX) 
EXTERNAL Name concat_assembly.[Concat.Concat]; 
GO  

sp_configure 'clr enabled', 1;
RECONFIGURE

어셈블리 경로가 서버에 액세스 할 수 있음을 관찰하십시오. 모든 단계를 성공적으로 수행 했으므로 다음과 같은 기능을 사용할 수 있습니다.

SELECT dbo.Concat(field1, ',')
FROM Table1

도움이되기를 바랍니다 !!!

나는 일반적으로 SQL Server의 문자열을 연결하기 위해 다음과 같이 선택합니다.

with lines as 
( 
  select 
    row_number() over(order by id) id, -- id is a line id
    line -- line of text.
  from
    source -- line source
), 
result_lines as 
( 
  select 
    id, 
    cast(line as nvarchar(max)) line 
  from 
    lines 
  where 
    id = 1 
  union all 
  select 
    l.id, 
    cast(r.line + N', ' + l.line as nvarchar(max))
  from 
    lines l 
    inner join 
    result_lines r 
    on 
      l.id = r.id + 1 
) 
select top 1 
  line
from
  result_lines
order by
  id desc

당신이 널을 처리하려면, where 절을 추가하거나 첫 번째 코스를 추가하여 할 수 있습니다.

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People

MySQL 완료 예 :

우리는 많은 데이터를 가질 수있는 사용자가 있고 출력을 원합니다. 여기서 모든 사용자 데이터를 목록에서 볼 수 있습니다.

결과:

___________________________
| id   |  rowList         |
|-------------------------|
| 0    | 6, 9             |
| 1    | 1,2,3,4,5,7,8,1  |
|_________________________|

테이블 설정 :

CREATE TABLE `Data` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;


INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);


CREATE TABLE `User` (
  `id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `User` (`id`) VALUES
(0),
(1);

질문:

SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id

오라클에서는입니다 wm_concat. 이 기능은이 기능을 사용할 수 있다고 생각합니다 10G 릴리스 그리고 더 높습니다.

이것도 유용 할 수 있습니다

create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')

DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test

보고

Peter,Paul,Mary

이 방법은 NPATH 기능을 사용하므로 Teradata Aster 데이터베이스에만 적용됩니다.

다시, 우리는 테이블 학생들이 있습니다

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

그런 다음 npath를 사용하면 단일 선택입니다.

SELECT * FROM npath(
  ON Students
  PARTITION BY SubjectID
  ORDER BY StudentName
  MODE(nonoverlapping)
  PATTERN('A*')
  SYMBOLS(
    'true' as A
  )
  RESULT(
    FIRST(SubjectID of A) as SubjectID,
    ACCUMULATE(StudentName of A) as StudentName
  )
);

결과:

SubjectID       StudentName
----------      -------------
1               [John, Mary, Sam]
2               [Alaina, Edward]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top