Considérons une table de base de données contenant des noms, avec trois lignes:
Peter
Paul
Mary
Existe-t-il un moyen simple de transformer cela en une seule chaîne de Peter, Paul, Mary
?
Si vous êtes sur SQL Server 2017 ou Azure, voir réponse de Mathieu Renda .
J'avais un problème similaire lorsque j'essayais de joindre deux tables avec des relations un à plusieurs. En SQL 2005, j’ai constaté que la méthode XML PATH
peut gérer très facilement la concaténation des lignes.
S'il y a une table appelée STUDENTS
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
Le résultat que j'attendais était:
SubjectID StudentName
---------- -------------
1 Mary, John, Sam
2 Alaina, Edward
J'ai utilisé le T-SQL
suivant:
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]
Vous pouvez faire la même chose d'une manière plus compacte si vous pouvez concattre les virgules au début et utiliser substring
pour ignorer la première, de sorte que vous n'avez pas besoin de faire une sous-requête:
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
Cette réponse peut renvoyer résultats inattendus Pour obtenir des résultats cohérents, utilisez l'une des méthodes FOR XML PATH décrites dans d'autres réponses.
Utilisez COALESCE
:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
Juste une explication (puisque cette réponse semble avoir des vues relativement régulières):
1) Pas besoin d'initialiser @Names
avec une valeur de chaîne vide.
2) Pas besoin de retirer un séparateur supplémentaire à la fin.
@Names
NULL après cette ligne, et la ligne suivante recommencera comme une chaîne vide à nouveau. Facilement réparable avec l’une des deux solutions suivantes:DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL
ou:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') +
ISNULL(Name, 'N/A')
FROM People
En fonction du comportement souhaité (la première option ne filtre que NULL), la deuxième option les conserve dans la liste avec un message de marqueur [remplacez "N/A" par tout ce qui est approprié pour vous]).
Une méthode non encore affichée via la commande XML
data()
dans MS SQL Server est la suivante:
Suppose la table appelée NameList avec une colonne appelée FName,
SELECT FName + ', ' AS 'data()'
FROM NameList
FOR XML PATH('')
résultats:
"Peter, Paul, Mary, "
Seule la virgule supplémentaire doit être traitée.
Edit: Comme adopté dans le commentaire de @ NReilingh, vous pouvez utiliser la méthode suivante pour supprimer la virgule de fin. En supposant les mêmes noms de table et de colonne:
STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
À partir de la prochaine version de SQL Server, nous pouvons enfin concaténer des lignes sans avoir à recourir à une variable ou à une sorcellerie XML.
sans regroupement
SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;
Avec regroupement:
SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
avec regroupement et sous-tri
SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
SELECT Stuff(
(SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
vous pouvez utiliser le FOR JSON syntaxe
c'est à dire.
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
Et le résultat deviendra
Id Emails
1 [email protected]
2 NULL
3 [email protected], [email protected]
Cela fonctionnera même si vos données contiennent des caractères XML non valides.
le '"},{"_":"'
est sécurisé, car si vos données contiennent '"},{"_":"',
, il sera échappé à "},{\"_\":\"
Vous pouvez remplacer ', '
par tout séparateur de chaîne
Vous pouvez utiliser le nouveau fonction STRING_AGG
Dans MySQL, il existe une fonction, GROUP_CONCAT () , qui vous permet de concaténer les valeurs de plusieurs lignes. Exemple:
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
Utilisez COALESCE - En savoir plus à partir d'ici
Par exemple:
102
103
104
Ensuite, écrivez ci-dessous le code dans le serveur 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
La sortie serait:
102,103,104
Les tableaux Postgres sont géniaux. Exemple:
Créer des données de test:
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)
Les regrouper dans un tableau:
test=# select array_agg(name) from names;
array_agg
-------------------
{Peter,Paul,Mary}
(1 row)
Convertissez le tableau en chaîne délimitée par des virgules:
test=# select array_to_string(array_agg(name), ', ') from names;
array_to_string
-------------------
Peter, Paul, Mary
(1 row)
TERMINÉ
Depuis PostgreSQL 9.0, il est encore plus facile .
Oracle 11g version 2 prend en charge la fonction LISTAGG. Documentation ici .
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.
Soyez prudent lors de l'implémentation de cette fonction s'il est possible que la chaîne résultante dépasse 4 000 caractères. Il va lancer une exception. Si tel est le cas, vous devez gérer l'exception ou lancer votre propre fonction qui empêche la chaîne jointe de dépasser 4 000 caractères.
Dans SQL Server 2005 et versions ultérieures, utilisez la requête ci-dessous pour concaténer les lignes.
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
Je n’ai pas accès à un serveur SQL à la maison, alors je suppose que la syntaxe est la suivante, mais c’est plus ou moins:
DECLARE @names VARCHAR(500)
SELECT @names = @names + ' ' + Name
FROM Names
Vous devez créer une variable qui contiendra votre résultat final et la sélectionnera comme ceci.
DECLARE @char VARCHAR(MAX);
SELECT @char = COALESCE(@char + ', ' + [column], [column])
FROM [table];
PRINT @char;
Une solution CTE récursive a été suggérée, mais aucun code n'a été fourni. Le code ci-dessous est un exemple de CTE récursif. Notez que, bien que les résultats correspondent à la question, les données ne correspondent pas tout à fait à la description donnée, car je suppose que vous voulez vraiment le faire sur des groupes de lignes, pas sur toutes les lignes de la table. Le changer pour qu'il corresponde à toutes les lignes du tableau reste un exercice pour le lecteur.
;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
À partir de PostgreSQL 9.0, ceci est assez simple:
select string_agg(name, ',')
from names;
Dans les versions antérieures à 9.0, array_agg()
peut être utilisé comme indiqué par hgmnz.
Dans SQL Server vNext, cette fonction sera intégrée à la fonction STRING_AGG. Pour en savoir plus, cliquez ici: https://msdn.Microsoft.com/en-us/library/mt790580.aspx
Utiliser XML m'a aidé à obtenir des lignes séparées par des virgules. Pour la virgule supplémentaire, nous pouvons utiliser la fonction de remplacement de SQL Server. Au lieu d'ajouter une virgule, l'utilisation de l'AS 'data ()' concaténera les lignes avec des espaces, qui pourront être remplacés ultérieurement par des virgules, comme indiqué ci-dessous.
REPLACE(
(select FName AS 'data()' from NameList for xml path(''))
, ' ', ', ')
Une solution prête à l'emploi, sans virgule supplémentaire:
select substring(
(select ', '+Name AS 'data()' from Names for xml path(''))
,3, 255) as "MyList"
Une liste vide entraînera une valeur NULL. Habituellement, vous insérez la liste dans une colonne de table ou une variable de programme: ajustez la longueur maximale de 255 à vos besoins.
(Diwakar et Jens Frandsen ont fourni de bonnes réponses, mais doivent être améliorées.)
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')
Voici un exemple:
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)
Cela met la virgule parasite au début.
Toutefois, si vous avez besoin d'autres colonnes, ou pour créer une table enfant au format CSV, vous devez envelopper cette opération dans un champ défini par l'utilisateur scalaire (UDF).
Vous pouvez également utiliser le chemin XML en tant que sous-requête corrélée dans la clause SELECT (mais je devrai attendre jusqu'à ce que je retourne au travail car Google ne fonctionne pas à la maison :-)
Avec les autres réponses, la personne qui lit la réponse doit connaître un tableau de domaine spécifique, tel que véhicule ou élève. La table doit être créée et renseignée avec des données pour tester une solution.
Vous trouverez ci-dessous un exemple d'utilisation de la table "Information_Schema.Columns" de SQL Server. En utilisant cette solution, il n'est pas nécessaire de créer de tables ni d'ajouter de données. Cet exemple crée une liste de noms de colonnes séparés par des virgules pour toutes les tables de la base de données.
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
Pour les bases de données Oracle, consultez la question suivante: Comment concaténer plusieurs lignes en une ligne dans Oracle sans créer de procédure stockée?
La meilleure réponse semble être celle de @Emmanuel, à l'aide de la fonction intégrée LISTAGG (), disponible dans Oracle 11g version 2 et ultérieure.
SELECT question_id,
LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id
comme @ user762952 l’a fait remarquer, et selon la documentation d’Oracle http://www.Oracle-base.com/articles/misc/string-aggregation-techniques.php , la fonction WM_CONCAT () est également une fonction option. Cela semble stable, mais Oracle recommande explicitement de ne pas l'utiliser pour toute application SQL, utilisez-le donc à vos risques et périls.
Autre que cela, vous devrez écrire votre propre fonction; Le document Oracle ci-dessus contient un guide expliquant comment procéder.
J'ai vraiment aimé l'élégance de réponse de Dana . Je voulais juste le rendre complet.
DECLARE @names VARCHAR(MAX)
SET @names = ''
SELECT @names = @names + ', ' + Name FROM Names
-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
Pour éviter les valeurs NULL, vous pouvez utiliser CONCAT ()
DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name)
FROM Names
select @names
Cette réponse nécessitera certains privilèges sur le serveur pour fonctionner.
Assemblies sont une bonne option pour vous. Il y a beaucoup de sites qui expliquent comment le créer. Celui que je pense est très bien expliqué est ceci n
Si vous le souhaitez, j'ai déjà créé l'assembly et il est possible de télécharger le fichier DLL ici .
Une fois que vous l'avez téléchargé, vous devrez exécuter le script suivant sur votre serveur 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
Observez que le chemin d'accès à Assembly peut être accessible au serveur. Comme vous avez réussi toutes les étapes, vous pouvez utiliser la fonction comme:
SELECT dbo.Concat(field1, ',')
FROM Table1
J'espère que ça aide!!!
J'utilise habituellement select comme ceci pour concaténer des chaînes dans 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
Exemple complet avec MySQL:
Nous avons des utilisateurs qui peuvent avoir plusieurs données et nous voulons une sortie, où nous pouvons voir toutes les données des utilisateurs dans une liste:
Résultat:
___________________________
| id | rowList |
|-------------------------|
| 0 | 6, 9 |
| 1 | 1,2,3,4,5,7,8,1 |
|_________________________|
Configuration de la table:
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);
Requête:
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
Si vous souhaitez traiter les valeurs null, vous pouvez le faire en ajoutant une clause where ou en ajoutant une autre COALESCE autour de la première.
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
Cela peut être utile aussi
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
résultats
Peter,Paul,Mary
Dans Oracle, il s'agit de wm_concat
. Je crois que cette fonction est disponible dans la version version 10g et supérieure.
Cette méthode s'applique à la base de données Teradata Aster uniquement dans la mesure où elle utilise sa fonction NPATH.
Encore une fois, nous avons des étudiants de table
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
Ensuite, avec NPATH, il n’ya qu’un simple SELECT:
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
)
);
Résultat:
SubjectID StudentName
---------- -------------
1 [John, Mary, Sam]
2 [Alaina, Edward]
Ce n’est pas que j’ai fait d’analyse de la performance, car ma liste comptait moins de 10 éléments, mais j’ai été étonné d’avoir parcouru une trentaine de réponses étranges. Il n'est même pas nécessaire de définir ma variable (la valeur par défaut est NULL de toute façon) et cela suppose que toutes les entrées de la table de données source ne sont pas vides:
DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData
Je suis sûr que COALESCE utilise en interne la même idée. Espérons que MS ne changera pas cela pour moi.
Voici la solution complète pour y parvenir:
-- Table Creation
CREATE TABLE Tbl
( CustomerCode VARCHAR(50)
, CustomerName VARCHAR(50)
, Type VARCHAR(50)
,Items VARCHAR(50)
)
insert into Tbl
SELECT 'C0001','Thomas','BREAKFAST','Milk'
union SELECT 'C0001','Thomas','BREAKFAST','Bread'
union SELECT 'C0001','Thomas','BREAKFAST','Egg'
union SELECT 'C0001','Thomas','LUNCH','Rice'
union SELECT 'C0001','Thomas','LUNCH','Fish Curry'
union SELECT 'C0001','Thomas','LUNCH','Lessy'
union SELECT 'C0002','JOSEPH','BREAKFAST','Bread'
union SELECT 'C0002','JOSEPH','BREAKFAST','Jam'
union SELECT 'C0002','JOSEPH','BREAKFAST','Tea'
union SELECT 'C0002','JOSEPH','Supper','Tea'
union SELECT 'C0002','JOSEPH','Brunch','Roti'
-- function creation
GO
CREATE FUNCTION [dbo].[fn_GetItemsByType]
(
@CustomerCode VARCHAR(50)
,@Type VARCHAR(50)
)
RETURNS @ItemType TABLE ( Items VARCHAR(5000) )
AS
BEGIN
INSERT INTO @ItemType(Items)
SELECT STUFF((SELECT distinct ',' + [Items]
FROM Tbl
WHERE CustomerCode = @CustomerCode
AND Type=@Type
FOR XML PATH(''))
,1,1,'') as Items
RETURN
END
GO
-- fianl Query
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Type)
from Tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT CustomerCode,CustomerName,' + @cols + '
from
(
select
distinct CustomerCode
,CustomerName
,Type
,F.Items
FROM Tbl T
CROSS APPLY [fn_GetItemsByType] (T.CustomerCode,T.Type) F
) x
pivot
(
max(Items)
for Type in (' + @cols + ')
) p '
execute(@query)
--SQL Server 2005+
CREATE TABLE dbo.Students
(
StudentId INT
, Name VARCHAR(50)
, CONSTRAINT PK_Students PRIMARY KEY (StudentId)
);
CREATE TABLE dbo.Subjects
(
SubjectId INT
, Name VARCHAR(50)
, CONSTRAINT PK_Subjects PRIMARY KEY (SubjectId)
);
CREATE TABLE dbo.Schedules
(
StudentId INT
, SubjectId INT
, CONSTRAINT PK__Schedule PRIMARY KEY (StudentId, SubjectId)
, CONSTRAINT FK_Schedule_Students FOREIGN KEY (StudentId) REFERENCES dbo.Students (StudentId)
, CONSTRAINT FK_Schedule_Subjects FOREIGN KEY (SubjectId) REFERENCES dbo.Subjects (SubjectId)
);
INSERT dbo.Students (StudentId, Name) VALUES
(1, 'Mary')
, (2, 'John')
, (3, 'Sam')
, (4, 'Alaina')
, (5, 'Edward')
;
INSERT dbo.Subjects (SubjectId, Name) VALUES
(1, 'Physics')
, (2, 'Geography')
, (3, 'French')
, (4, 'Gymnastics')
;
INSERT dbo.Schedules (StudentId, SubjectId) VALUES
(1, 1) --Mary, Physics
, (2, 1) --John, Physics
, (3, 1) --Sam, Physics
, (4, 2) --Alaina, Geography
, (5, 2) --Edward, Geography
;
SELECT
sub.SubjectId
, sub.Name AS [SubjectName]
, ISNULL( x.Students, '') AS Students
FROM
dbo.Subjects sub
OUTER APPLY
(
SELECT
CASE ROW_NUMBER() OVER (ORDER BY stu.Name) WHEN 1 THEN '' ELSE ', ' END
+ stu.Name
FROM
dbo.Students stu
INNER JOIN dbo.Schedules sch
ON stu.StudentId = sch.StudentId
WHERE
sch.SubjectId = sub.SubjectId
ORDER BY
stu.Name
FOR XML PATH('')
) x (Students)
;
Que dis-tu de ça:
ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'
Où le "300" pourrait être n'importe quelle largeur en tenant compte du nombre maximum d'éléments que vous pensez apparaître.
Une façon de procéder dans SQL Server consiste à renvoyer le contenu de la table au format XML (pour XML brut), à convertir le résultat en chaîne, puis à remplacer les balises par ",".
SELECT PageContent = Stuff(
( SELECT PageContent
FROM dbo.InfoGuide
WHERE CategoryId = @CategoryId
AND SubCategoryId = @SubCategoryId
for xml path(''), type
).value('.[1]','nvarchar(max)'),
1, 1, '')
FROM dbo.InfoGuide info
Définition de la table
CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;
Insérons des valeurs dans ce tableau
INSERT INTO NAMES VALUES('PETER');
INSERT INTO NAMES VALUES('PAUL');
INSERT INTO NAMES VALUES('MARY');
La procédure commence à partir d'ici
DECLARE
MAXNUM INTEGER;
CNTR INTEGER := 1;
C_NAME NAMES.NAME%TYPE;
NSTR VARCHAR2(50);
BEGIN
SELECT MAX(ROWNUM) INTO MAXNUM FROM NAMES;
LOOP
SELECT NAME INTO C_NAME FROM
(SELECT ROWNUM RW, NAME FROM NAMES ) P WHERE P.RW = CNTR;
NSTR := NSTR ||','||C_NAME;
CNTR := CNTR + 1;
EXIT WHEN CNTR > MAXNUM;
END LOOP;
dbms_output.put_line(SUBSTR(NSTR,2));
END;
Résultat
PETER,PAUL,MARY
Bien qu'il soit trop tard, et a déjà de nombreuses solutions. Voici une solution simple pour MySQL:
SELECT t1.id,
GROUP_CONCAT(t1.id) ids
FROM table t1 JOIN table t2 ON (t1.id = t2.id)
GROUP BY t1.id
@ User1460901 Vous pouvez essayer quelque chose comme ceci:
WITH cte_base AS (
SELECT CustomerCode, CustomerName,
CASE WHEN Typez = 'Breakfast' THEN Items ELSE NULL END AS 'BREAKFAST'
, CASE WHEN Typez = 'Lunch' THEN Items ELSE NULL END AS 'LUNCH'
FROM #Customer
)
SELECT distinct CustomerCode, CustomerName,
SUBSTRING(
(
SELECT ','+BREAKFAST AS [text()]
FROM cte_base b1
WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
ORDER BY b1.BREAKFAST
FOR XML PATH('')
), 2, 1000
) [BREAKFAST],
SUBSTRING(
(
SELECT ','+LUNCH AS [text()]
FROM cte_base b1
WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
ORDER BY b1.LUNCH
FOR XML PATH('')
), 2, 1000
) [LUNCH]
FROM cte_base b2
Avec le type TABLE, c'est extrêmement facile. Imaginons que votre table s'appelle Students
et qu'elle ait la colonne name
.
declare @rowsCount INT
declare @i INT = 1
declare @names varchar(max) = ''
DECLARE @MyTable TABLE
(
Id int identity,
Name varchar(500)
)
insert into @MyTable select name from Students
set @rowsCount = (select COUNT(Id) from @MyTable)
while @i < @rowsCount
begin
set @names = @names + ', ' + (select name from @MyTable where Id = @i)
set @i = @i + 1
end
select @names
Cet exemple est testé dans MS SQL Server 2008 R2
Avec une requête récursive, vous pouvez le faire:
-- Create example table
CREATE TABLE tmptable (NAME VARCHAR(30)) ;
-- Insert example data
INSERT INTO tmptable VALUES('PETER');
INSERT INTO tmptable VALUES('PAUL');
INSERT INTO tmptable VALUES('MARY');
-- Recurse query
with tblwithrank as (
select * , row_number() over(order by name) rang , count(*) over() NbRow
from tmptable
),
tmpRecursive as (
select *, cast(name as varchar(2000)) as AllName from tblwithrank where rang=1
union all
select f0.*, cast(f0.name + ',' + f1.AllName as varchar(2000)) as AllName
from tblwithrank f0 inner join tmpRecursive f1 on f0.rang=f1.rang +1
)
select AllName from tmpRecursive
where rang=NbRow
Il y a deux autres façons dans Oracle,
create table name
(first_name varchar2(30));
insert into name values ('Peter');
insert into name values ('Paul');
insert into name values ('Mary');
Solution 1:
select substr(max(sys_connect_by_path (first_name, ',')),2) from (select rownum r, first_name from name ) n start with r=1 connect by prior r+1=r
o/p=> Peter,Paul,Mary
Soution 2:
select rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
o/p=> Peter,Paul,Mary
Nous pouvons utiliser RECUSRSIVITY, WITH CTE, ALL ALL comme suit
declare @mytable as table(id int identity(1,1), str nvarchar(100))
insert into @mytable values('Peter'),('Paul'),('Mary')
declare @myresult as table(id int,str nvarchar(max),ind int, R# int)
;with cte as(select id,cast(str as nvarchar(100)) as str, cast(0 as int) ind from @mytable
union all
select t2.id,cast(t1.str+',' +t2.str as nvarchar(100)) ,t1.ind+1 from cte t1 inner join @mytable t2 on t2.id=t1.id+1)
insert into @myresult select *,row_number() over(order by ind) R# from cte
select top 1 str from @myresult order by R# desc
sur la réponse de Chris Shaffer
si vos données peuvent être répétées telles que
Tom
ALi
John
ALi
Tom
Mike
Au lieu d'avoir Tom,ALi,John,ALi,Tom,Mike
Vous pouvez utiliser DISTINCT pour éviter les doublons et obtenir Tom,ALi,John,Mike
DECLARE @Names VARCHAR(8000)
SELECT DISTINCT @Names = COALESCE(@Names + ',', '') + Name
FROM People
WHERE Name IS NOT NULL
SELECT @Names