세 개의 행이있는 이름을 보유한 데이터베이스 테이블을 고려하십시오.
Peter
Paul
Mary
이것을 단일 문자열로 바꾸는 쉬운 방법이 Peter, Paul, Mary
있습니까?
세 개의 행이있는 이름을 보유한 데이터베이스 테이블을 고려하십시오.
Peter
Paul
Mary
이것을 단일 문자열로 바꾸는 쉬운 방법이 Peter, Paul, Mary
있습니까?
답변:
SQL Server 2017 또는 Azure를 사용하는 경우 Mathieu Renda answer를 참조하십시오 .
일대 다 관계로 두 테이블을 조인하려고 할 때 비슷한 문제가 발생했습니다. SQL 2005에서 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]
처음에 쉼표를 연결 substring
하고 첫 번째 쉼표 를 건너 뛰어 하위 쿼리를 수행 할 필요가없는 경우 더 간단한 방법으로 동일한 작업을 수행 할 수 있습니다.
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
<
나 &
. @BenHinman의 의견을 참조하십시오.
FOR XML PATH ('')
. 즉, 패치 나 업데이트로 인해이 기능이 변경 될 수 있으므로 신뢰할 수있는 것으로 간주해서는 안됩니다. 기본적으로 더 이상 사용되지 않는 기능에 의존합니다.
FOR XML
임의의 문자열을 연결하지 않고 XML을 생성하는 것입니다. 즉,이 탈출 이유 &
, <
그리고 >
XML 엔티티 코드로 ( &
, <
, >
). 나는 또한 탈출 것으로 가정 "
및 '
에 "
와 '
속성에뿐만 아니라. 그건 아니 GROUP_CONCAT()
, string_agg()
, array_agg()
, listagg()
, 등 당신은 어떤 메이크업의 그것은 그렇게 할 수 경우에도 마찬가지입니다. 우리 는 Microsoft가 적절한 기능을 구현하도록 요구하면서 시간을 보내야 합니다.
string_agg
v.Next에 추가 될 예정입니다. 이 모든 것이 사라질 수 있습니다.
이 답변은 예기치 않은 결과 를 반환 할 수 있습니다. 일관된 결과를 얻으려면 다른 답변에 자세히 나와있는 FOR XML PATH 메서드 중 하나를 사용하십시오.
사용 COALESCE
:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
약간의 설명 (이 답변은 상대적으로 규칙적인 견해를 갖기 때문에) :
1) @Names
빈 문자열 값 으로 초기화 할 필요가 없습니다 .
2) 끝에서 여분의 분리기를 떼어 낼 필요가 없습니다.
@Names
NULL을 해당 행 후, 다음 행은 다시 빈 문자열로 시작됩니다. 쉽게 두 가지 중 하나를 고정 솔루션 :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
원하는 동작에 따라 첫 번째 옵션은 NULL을 필터링 하므로 두 번째 옵션은 마커 메시지와 함께 목록에 유지합니다 ( 'N / A'를 적절한 것으로 바꿉니다).
다음 버전의 SQL Server부터는 변수 또는 XML 마녀에 의존하지 않고도 행 전체를 연결할 수 있습니다.
그룹화하지 않고
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;
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
+ ', '
연결된 모든 요소 사이에 단일 공백이 여전히 추가됩니다.
SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
SELECT Stuff(
(SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
FOR 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 문자가 포함되어 있어도 작동합니다.
은 '"},{"_":"'
당신의 데이터가 포함 된 경우 때문에 안전 '"},{"_":"',
이 탈출한다"},{\"_\":\"
', '
문자열 구분 기호로 바꿀 수 있습니다
새로운 STRING_AGG 기능을 사용할 수 있습니다
<
, >
, &
, 등 어떤 FOR XML PATH('')
자동으로 이스케이프됩니다.
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
SEPARATOR '", "'
하면 마지막 항목 끝에 일부 문자가 누락됩니다. 왜 이런 일이 일어날 수 있습니까?
CHAR
, 당신이 그것을 캐스팅 할 필요가, 예를 통해 GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')
2) 많은 값이 올 경우, 당신은 증가 할 전망 group_concat_max_len
에서 작성된 stackoverflow.com/a/1278210/1498405
COALESCE 사용 - 여기에서 자세히 알아보기
예를 들어 :
102
103
104
그런 다음 SQL 서버에서 아래 코드를 작성하십시오.
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
Declare @Numbers AS Nvarchar(MAX)
했고 잘 작동했다. 사용하지 않는 것이 좋은 이유를 설명해 주시겠습니까?
Postgres 어레이는 훌륭합니다. 예:
테스트 데이터를 작성하십시오.
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 이후로 훨씬 더 쉽습니다 .
select array_to_string(array_agg(name||'('||id||')'
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자를 넘지 않도록하는 고유 한 함수를 롤링해야합니다.
LISTAGG
완벽하게 작동합니다! 여기에 링크 된 문서를 읽으십시오. wm_concat
버전 12c 이상에서 제거되었습니다.
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
SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
SELECT @names = @names + ISNULL(' ' + Name, '')
재귀 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
name
열을 쉼표로 구분 된 4 개의 그룹 으로 묶습니다id
. 언뜻보기에 이것은 대부분의 다른 SQL Server 솔루션보다 더 많은 작업이라고 생각합니다.
PostgreSQL 9.0부터는 매우 간단합니다.
select string_agg(name, ',')
from names;
9.0 이전의 버전에서는 array_agg()
hgmnz로 표시된대로 사용할 수 있습니다.
SELECT string_agg(non_text_type::text, ',') FROM table
varchar
또는char
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"
빈 목록은 NULL 값이됩니다. 일반적으로 목록을 테이블 열 또는 프로그램 변수에 삽입합니다. 필요에 따라 255 최대 길이를 조정하십시오.
Diwakar와 Jens Frandsen은 좋은 답변을 제공했지만 개선이 필요합니다.
', '
와 함께 ','
당신이 여분의 공간을하지 않으려면.
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)
이렇게하면 시작 부분에 쉼표가 표시됩니다.
그러나 다른 열이 필요하거나 하위 테이블을 CSV로 만들려면이를 스칼라 사용자 정의 필드 (UDF)로 랩핑해야합니다.
SELECT 절에서 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 DB의 경우이 질문을 참조하십시오 . 저장 프로 시저를 작성하지 않고 Oracle에서 여러 행을 하나로 연결할 수 있습니까?
@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가 지적했듯이 오라클의 문서 http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php 에 따르면 에 따르면 WM_CONCAT () 함수도 옵션입니다. 안정된 것처럼 보이지만 Oracle은 명시 적으로 응용 프로그램 SQL에 사용하지 않는 것이 좋으므로 위험 부담으로 사용하십시오.
그 외에는 자신의 기능을 작성해야합니다. 위의 Oracle 문서에는이를 수행하는 방법에 대한 안내서가 있습니다.
나는 Dana의 대답의 우아함을 정말로 좋아했습니다 . 그냥 완성하고 싶었습니다.
DECLARE @names VARCHAR(MAX)
SET @names = ''
SELECT @names = @names + ', ' + Name FROM Names
-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Names
다음 나중에 잘리지 않아도됩니다.
이 답변을 사용하려면 서버에서 일부 권한이 필요합니다.
어셈블리 는 좋은 옵션입니다. 작성 방법을 설명하는 사이트가 많이 있습니다. 나는 아주 잘 설명되어 생각 하나는 이것이다 하나
원하는 경우 이미 어셈블리를 만들었으며 여기 에서 DLL을 다운로드 할 수 있습니다 .
다운로드 한 후에는 SQL Server에서 다음 스크립트를 실행해야합니다.
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
도움이 되길 바랍니다 !!!
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
일반적으로 SQL Server에서 문자열을 연결하기 위해 다음과 같이 select를 사용합니다.
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
이것은 나를 위해 일했습니다 ( SqlServer 2016 ).
SELECT CarNamesString = STUFF((
SELECT ',' + [Name]
FROM tbl_cars
FOR XML PATH('')
), 1, 1, '')
여기 소스가 있습니다 : https://www.mytecbits.com/
그리고 MySql에 대한 솔루션 (이 페이지는 MySql 용 Google에 표시되므로)
SELECT [Name],
GROUP_CONCAT(DISTINCT [Name] SEPARATOR ',')
FROM tbl_cars
에서 MySQL의 자료 문서
이것도 유용 할 수 있습니다
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