Concaténation des champs dans différentes lignes
-
20-09-2019 - |
Question
Je suis bloqué sur un problème d'agrégation que je ne peux pas aller au fond de.
J'ai des données qui est le mieux résumée comme suit
id |phraseId|seqNum|word
=========================
1 |1 |1 |hello
2 |1 |2 |world
3 |2 |1 |black
4 |2 |2 |and
5 |2 |3 |white
Je voudrais une requête qui rend les données suivantes:
phraseId|completePhrase
========================
1 |hello world
2 |black and white
Tout le monde?
EDIT
Je remarque toutes les solutions proposées utilisent FOR XML PATH
. Qu'est-ce que cette magie?
La solution
Une solution consiste à créer un UDF en utilisant un pour l'expression de XML PATH.
- l'UDF gère la concaténation d'un PhraseID
- il peut être utilisé dans une sélection normale
Déclaration SQL
SELECT PhraseID, dbo.UDF_ConcatWord(PhraseID)
FROM Phrases
GROUP BY PhraseID
Création de l'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
modifier
Après avoir révisé certains des liens moi-même, est
une solution encore plus courteDéclaration 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
Autres conseils
essayez ceci:
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
SORTIE:
phraseId CombinedValue
-------- --------------------------
1 hello world
2 black and white
(2 row(s) affected)
Je suis un peu triché en supposant que vous avez une table qui détient le record d'en-tête pour chaque phrase. Si ce manque, vous pouvez construire en sélectionnant une liste distincte de phraseIDs de la table contenant les mots:
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)
En fin de compte, j'utilisé la deuxième réponse de Lieven, mais a constaté que pour certaines combinaisons de chaînes, l'astuce de FOR XML PATH('')
provoque des problèmes de se produire:
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
fonctionne très bien, mais si l'exemple utilise des caractères qui ont besoin à s'échapper étaient-ils utilisés dans un fichier XML, des problèmes surviennent. Par exemple, les données en cours d'exécution suivantes à travers elle:
insert
@words
values
(1,1,1,'hello>'), --notice the less than symbol
(2,1,2,'world'),
(3,2,1,'black')
Donne
hello> world
et même si la table source est déclarée hors d'usage, un order by
est nécessaire
Un petit mod à la requête initiale fixe tous:
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