다른 행에서 필드를 연결합니다
-
20-09-2019 - |
문제
나는 바닥에 도달 할 수없는 집계 문제에 갇혀 있습니다.
다음과 같이 가장 잘 요약 된 데이터가 있습니다.
id |phraseId|seqNum|word
=========================
1 |1 |1 |hello
2 |1 |2 |world
3 |2 |1 |black
4 |2 |2 |and
5 |2 |3 |white
다음 데이터를 돌려주는 쿼리를 원합니다.
phraseId|completePhrase
========================
1 |hello world
2 |black and white
누구나?
편집하다
제공된 모든 솔루션이 사용되는 것을 알 수 있습니다 FOR XML PATH
. 이 마법은 무엇입니까?
해결책
한 가지 해결책은 UDF 사용 XML 경로의 경우 표현.
- UDF는 하나의 문자의 연결을 처리합니다
- 정상적인 선택에서 사용할 수 있습니다
SQL 문
SELECT PhraseID, dbo.UDF_ConcatWord(PhraseID)
FROM Phrases
GROUP BY PhraseID
UDF 생성
CREATE FUNCTION dbo.UDF_ConcatWord(@phraseID INT) RETURNS VARCHAR(8000) AS
BEGIN
DECLARE @r VARCHAR(8000)
SELECT @r = (
SELECT word + ', '
FROM Phrases
WHERE phraseID = @phraseID
FOR XML PATH('')
)
IF LEN(@r) > 0 SET @r = SUBSTRING(@r, 1, LEN(@r)-1)
RETURN @r
END
GO
편집하다
일부 링크를 직접 수정 한 후에는 더 짧은 솔루션이
SQL 문
SELECT DISTINCT p1.PhraseID
, STUFF(( SELECT ' ' + p2.word
FROM Phrases AS p2
WHERE p2.PhraseID = p1.PhraseID
FOR XML PATH('')), 1, 1, '') AS completePhrase
FROM Phrases AS p1
ORDER BY p1.PhraseID
다른 팁
이 시도:
DECLARE @TableA table (RowID int, phraseId varchar(5),seqNum int, word varchar(5))
INSERT INTO @TableA VALUES (1,1,1,'hello')
INSERT INTO @TableA VALUES (2,1,2,'world')
INSERT INTO @TableA VALUES (3,2,1,'black')
INSERT INTO @TableA VALUES (4,2,2,'and')
INSERT INTO @TableA VALUES (5,2,3,'white')
SELECT
c1.phraseId
,STUFF(
(SELECT
' ' + word
FROM @TableA c2
WHERE c2.phraseId=c1.phraseId
ORDER BY c1.phraseId, seqNum
FOR XML PATH('')
)
,1,1, ''
) AS CombinedValue
FROM @TableA c1
GROUP BY c1.phraseId
ORDER BY c1.phraseId
산출:
phraseId CombinedValue
-------- --------------------------
1 hello world
2 black and white
(2 row(s) affected)
각 문구에 대한 헤더 레코드를 보유하는 테이블이 있다고 가정하여 조금 부정했습니다. 누락 된 경우, 단어가 포함 된 테이블에서 뚜렷한 문구 목록을 선택하여 구성 할 수 있습니다.
declare @words table
(id int
,phraseId int
,seqNum int
,word varchar(10)
)
insert @words
select 1,1,1,'hello'
union select 2,1,2,'world'
union select 3,2,1,'black'
union select 4,2,2,'and'
union select 5,2,4,'white'
declare @phrase table
(phraseId int)
insert @phrase
select 1
union select 2
select phraseID
,phraseText AS completePhrase
FROM @phrase AS p
CROSS APPLY (select word + ' ' as [text()]
from @words AS w
where w.phraseID = p.phraseID
for xml path('')
) as phrases (phraseText)
결국 나는 Lieven의 두 번째 대답을 사용했지만 특정 문자열 조합에 대해 FOR XML PATH('')
속임수는 문제가 발생합니다.
declare @phrases table
(
id int
,phraseId int
,seqNum int
,word varchar(10)
)
insert
@phrases
values
(1,1,1,'hello'),
(2,1,2,'world'),
(3,2,1,'black'),
(4,2,2,'and'),
(5,2,3,'white')
SELECT
DISTINCT p1.PhraseID,
STUFF(
(
SELECT
' ' + p2.word
FROM
@phrases AS p2
WHERE
p2.PhraseID = p1.PhraseID
FOR XML PATH('')
), 1, 1, '') AS completePhrase
FROM
@phrases AS p1
ORDER BY
p1.PhraseID
잘 작동하지만이 예제가 탈출이 필요한 문자를 사용하면 XML에 사용 된 경우 문제가 발생합니다. 예를 들어, 다음을 통해 다음 데이터를 실행합니다.
insert
@words
values
(1,1,1,'hello>'), --notice the less than symbol
(2,1,2,'world'),
(3,2,1,'black')
주어진
hello> world
또한 소스 테이블이 순서대로 선언되면 order by
필요합니다
원래 쿼리에 대한 작은 모드는 모든 것을 수정합니다.
SELECT
DISTINCT p1.PhraseID,
STUFF(
(
SELECT
' ' + p2.word
FROM
@words AS p2
WHERE
p2.PhraseID = p1.PhraseID
ORDER BY
p2.seqNum --required
FOR XML PATH(''),TYPE
).value('.','nvarchar(4000)'),
1,
1,
''
) AS completePhrase
FROM
@words AS p1
ORDER BY
p1.PhraseID
제휴하지 않습니다 StackOverflow