Betrachten Sie eine Datenbanktabelle mit Namen und drei Zeilen:
Peter
Paul
Mary
Gibt es eine einfache Möglichkeit, dies in eine einzelne Zeichenfolge von Peter, Paul, Mary
umzuwandeln?
Wenn Sie mit SQL Server 2017 oder Azure arbeiten, lesen Sie Antwort von Mathieu Renda .
Ich hatte ein ähnliches Problem, als ich versuchte, zwei Tabellen mit Eins-zu-Viele-Beziehungen zu verknüpfen. In SQL 2005 stellte ich fest, dass die XML PATH
-Methode die Verkettung der Zeilen sehr einfach handhaben kann.
Wenn es eine Tabelle mit dem Namen STUDENTS
gibt
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
Ergebnis, das ich erwartet hatte, war:
SubjectID StudentName
---------- -------------
1 Mary, John, Sam
2 Alaina, Edward
Ich habe den folgenden T-SQL
verwendet:
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]
Sie können das Gleiche auf kompaktere Weise tun, wenn Sie die Kommas am Anfang einschließen und substring
verwenden, um das erste zu überspringen, sodass Sie keine Unterabfrage ausführen müssen:
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
Diese Antwort kann nerwartete Ergebnisse zurückgeben. Verwenden Sie für konsistente Ergebnisse eine der FOR XML PATH-Methoden, die in anderen Antworten aufgeführt sind.
Verwenden Sie COALESCE
:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
Nur eine Erklärung (da diese Antwort relativ regelmäßige Ansichten zu bekommen scheint):
1) Es ist nicht erforderlich, @Names
mit einem leeren Zeichenfolgenwert zu initialisieren.
2) Am Ende muss kein zusätzlicher Abscheider entfernt werden.
@Names
NULL nach dieser Zeile, und die nächste Zeile beginnt von vorne als wieder eine leere Zeichenfolge. Mit einer von zwei Lösungen leicht zu beheben:DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL
oder:
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(@Names + ', ', '') +
ISNULL(Name, 'N/A')
FROM People
Je nachdem, welches Verhalten Sie wünschen (die erste Option filtert nur NULL aus, die zweite Option hält sie in der Liste mit einer Markierungsnachricht [Ersetzen Sie 'N/A' durch was auch immer für dich angemessen ist]).
Eine Methode, die noch nicht über den Befehl XML
data()
in MS SQL Server angezeigt wird, ist:
Angenommen, die Tabelle heißt NameList und eine Spalte heißt FName.
SELECT FName + ', ' AS 'data()'
FROM NameList
FOR XML PATH('')
kehrt zurück:
"Peter, Paul, Mary, "
Nur das zusätzliche Komma muss behandelt werden.
Edit: Wie in @ NReilinghs Kommentar übernommen, können Sie das nachstehende Komma mit der folgenden Methode entfernen. Angenommen, die gleichen Tabellen- und Spaltennamen:
STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands
Ab der nächsten Version von SQL Server können wir endlich zeilenübergreifend verketten, ohne auf Variablen oder XML-Hexerei zurückgreifen zu müssen.
Ohne Gruppierung
SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;
Mit Gruppierung:
SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;
Mit Gruppierung und Untersortierung
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'')
sie können die FOR JSON-Syntax verwenden
d.h.
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
Und das Ergebnis wird
Id Emails
1 [email protected]
2 NULL
3 [email protected], [email protected]
Dies funktioniert auch dann, wenn Ihre Daten ungültige XML-Zeichen enthalten
der '"},{"_":"'
ist sicher, denn wenn Ihre Daten '"},{"_":"',
enthalten, werden sie an "},{\"_\":\"
weitergeleitet.
Sie können ', '
durch ein beliebiges Zeichenfolgentrennzeichen ersetzen
Sie können die neue STRING_AGG-Funktion verwenden
In MySQL gibt es eine Funktion GROUP_CONCAT () , mit der Sie die Werte aus mehreren Zeilen zusammenfassen können. Beispiel:
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
Verwenden Sie COALESCE - Weitere Informationen finden Sie hier
Zum Beispiel:
102
103
104
Dann schreiben Sie unten Code in 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
Die Ausgabe wäre:
102,103,104
Postgres-Arrays sind fantastisch. Beispiel:
Erstellen Sie einige Testdaten:
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)
Aggregieren Sie sie in einem Array:
test=# select array_agg(name) from names;
array_agg
-------------------
{Peter,Paul,Mary}
(1 row)
Konvertieren Sie das Array in eine durch Kommas getrennte Zeichenfolge:
test=# select array_to_string(array_agg(name), ', ') from names;
array_to_string
-------------------
Peter, Paul, Mary
(1 row)
GETAN
Seit PostgreSQL 9.0 ist es noch einfacher .
Oracle 11g Release 2 unterstützt die LISTAGG-Funktion. Dokumentation hier .
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.
Seien Sie vorsichtig bei der Implementierung dieser Funktion, wenn die Möglichkeit besteht, dass die resultierende Zeichenfolge mehr als 4000 Zeichen umfasst. Es wird eine Ausnahme auslösen. In diesem Fall müssen Sie entweder die Ausnahme behandeln oder eine eigene Funktion ausführen, die verhindert, dass die verknüpfte Zeichenfolge mehr als 4000 Zeichen enthält.
Verwenden Sie in SQL Server 2005 und höher die folgende Abfrage, um die Zeilen zu verketten.
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
Ich habe zu Hause keinen Zugriff auf einen SQL Server, daher schätze ich die Syntax hier, aber es ist mehr oder weniger:
DECLARE @names VARCHAR(500)
SELECT @names = @names + ' ' + Name
FROM Names
Sie müssen eine Variable erstellen, die Ihr Endergebnis enthält, und diese wie folgt auswählen.
DECLARE @char VARCHAR(MAX);
SELECT @char = COALESCE(@char + ', ' + [column], [column])
FROM [table];
PRINT @char;
Eine rekursive CTE-Lösung wurde vorgeschlagen, es wurde jedoch kein Code bereitgestellt. Der folgende Code ist ein Beispiel für einen rekursiven CTE. Beachten Sie, dass, obwohl die Ergebnisse mit der Frage übereinstimmen, die Daten nicht ganz mit der angegebenen Beschreibung übereinstimmen, da ich davon ausgehe, dass Sie dies wirklich für Gruppen von Zeilen tun möchten, nicht für alle Zeilen in Der Tisch. Das Ändern, damit es mit allen Zeilen in der Tabelle übereinstimmt, wird dem Leser als Übung überlassen.
;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
Ab PostgreSQL 9.0 ist das ganz einfach:
select string_agg(name, ',')
from names;
In Versionen vor 9.0 kann array_agg()
wie von hgmnz gezeigt verwendet werden
In SQL Server vNext wird dies mit der STRING_AGG-Funktion integriert. Weitere Informationen hierzu finden Sie hier: https://msdn.Microsoft.com/en-us/library/mt790580.aspx
Die Verwendung von XML hat mir geholfen, Zeilen durch Kommas zu trennen. Für das zusätzliche Komma können wir die Ersetzungsfunktion von SQL Server verwenden. Anstatt ein Komma einzufügen, werden die Zeilen mit Leerzeichen verknüpft, die später durch Kommas ersetzt werden können (siehe unten).
REPLACE(
(select FName AS 'data()' from NameList for xml path(''))
, ' ', ', ')
Eine gebrauchsfertige Lösung ohne zusätzliche Kommas:
select substring(
(select ', '+Name AS 'data()' from Names for xml path(''))
,3, 255) as "MyList"
Eine leere Liste führt zu einem NULL-Wert. Normalerweise fügen Sie die Liste in eine Tabellenspalte oder Programmvariable ein: Passen Sie die maximale Länge von 255 an Ihre Bedürfnisse an.
(Diwakar und Jens Frandsen gaben gute Antworten, mussten aber verbessert werden.)
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')
Hier ist ein Beispiel:
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)
Damit steht das Streukomma am Anfang.
Wenn Sie jedoch andere Spalten oder eine untergeordnete Tabelle als CSV-Datei benötigen, müssen Sie diese in ein skalares benutzerdefiniertes Feld (UDF) einschließen.
Sie können den XML-Pfad auch als korrelierte Unterabfrage in der SELECT-Klausel verwenden (aber ich muss warten, bis ich wieder zur Arbeit gehe, da Google zu Hause keine Arbeit erledigt :-)
Bei den anderen Antworten muss der Person, die die Antwort liest, eine bestimmte Domänentabelle bekannt sein, z. B. Fahrzeug oder Schüler. Die Tabelle muss erstellt und mit Daten gefüllt werden, um eine Lösung zu testen.
Unten finden Sie ein Beispiel, das die SQL Server-Tabelle "Information_Schema.Columns" verwendet. Mit dieser Lösung müssen keine Tabellen erstellt oder Daten hinzugefügt werden. In diesem Beispiel wird eine durch Kommas getrennte Liste von Spaltennamen für alle Tabellen in der Datenbank erstellt.
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
Siehe für Oracle-DBs diese Frage: Wie können mehrere Zeilen in Oracle zu einer verkettet werden, ohne eine gespeicherte Prozedur zu erstellen?
Die beste Antwort scheint @Emmanuel zu sein, der die in Oracle 11g Release 2 und höher integrierte Funktion LISTAGG () verwendet.
SELECT question_id,
LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id
wie @ user762952 hervorhob und laut Oracle-Dokumentation http://www.Oracle-base.com/articles/misc/string-aggregation-techniques.php ist die WM_CONCAT () -Funktion auch eine Möglichkeit. Es scheint stabil zu sein, aber Oracle rät ausdrücklich davon ab, es für SQL-Anwendungen zu verwenden. Verwenden Sie es daher auf eigenes Risiko.
Ansonsten müssen Sie Ihre eigene Funktion schreiben. Das obige Oracle-Dokument enthält eine Anleitung dazu.
Ich mochte die Eleganz von Danas Antwort . Ich wollte es nur komplett machen.
DECLARE @names VARCHAR(MAX)
SET @names = ''
SELECT @names = @names + ', ' + Name FROM Names
-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
Um Nullwerte zu vermeiden, können Sie CONCAT () verwenden.
DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name)
FROM Names
select @names
Für diese Antwort sind einige Serverrechte erforderlich.
Assemblies sind eine gute Option für Sie. Es gibt viele Sites, die erklären, wie man es erstellt. Das, von dem ich denke, dass es sehr gut erklärt ist, ist dieses eins
Wenn Sie möchten, habe ich die Assembly bereits erstellt und es ist möglich, die DLL hier herunterzuladen.
Nachdem Sie es heruntergeladen haben, müssen Sie das folgende Skript in Ihrem SQL Server ausführen:
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
Beachten Sie, dass der Pfad zur Assembly möglicherweise für den Server zugänglich ist. Nachdem Sie alle Schritte erfolgreich ausgeführt haben, können Sie die folgende Funktion verwenden:
SELECT dbo.Concat(field1, ',')
FROM Table1
Ich hoffe es hilft!!!
Normalerweise verwende ich select wie folgt, um Zeichenfolgen in SQL Server zu verketten:
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
Vollständiges MySQL-Beispiel:
Wir haben Benutzer, die viele Daten haben können, und wir möchten eine Ausgabe, in der wir alle Benutzerdaten in einer Liste sehen können:
Ergebnis:
___________________________
| id | rowList |
|-------------------------|
| 0 | 6, 9 |
| 1 | 1,2,3,4,5,7,8,1 |
|_________________________|
Tabelleneinstellung:
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);
Abfrage:
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
Wenn Sie mit Nullen umgehen möchten, können Sie eine where-Klausel hinzufügen oder eine weitere COALESCE-Klausel um die erste Klausel hinzufügen.
DECLARE @Names VARCHAR(8000)
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
Dies kann auch nützlich sein
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
kehrt zurück
Peter,Paul,Mary
In Oracle ist es wm_concat
. Ich glaube, dass diese Funktion in der 10g-Version und höher verfügbar ist.
Diese Methode gilt nur für Teradata Aster-Datenbanken, da die NPATH-Funktion verwendet wird.
Wieder haben wir Tischstudenten
SubjectID StudentName
---------- -------------
1 Mary
1 John
1 Sam
2 Alaina
2 Edward
Dann ist es bei NPATH nur noch Single 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
)
);
Ergebnis:
SubjectID StudentName
---------- -------------
1 [John, Mary, Sam]
2 [Alaina, Edward]
Nicht, dass ich eine Leistungsanalyse durchgeführt hätte, da meine Liste weniger als 10 Elemente enthielt, aber ich war erstaunt, nachdem ich die 30 ungeraden Antworten durchgesehen hatte. Ich hatte immer noch eine Wendung bei einer ähnlichen Antwort, die bereits gegeben wurde, ähnlich wie bei der Verwendung von COALESCE für eine einzelne Gruppenliste und nicht Ich muss meine Variable nicht einmal setzen (der Standardwert ist sowieso NULL) und es wird davon ausgegangen, dass alle Einträge in meiner Quelldatentabelle nicht leer sind:
DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData
Ich bin sicher, dass COALESCE intern dieselbe Idee verwendet. Hoffen wir, dass MS das an mir nicht ändert.
Hier ist die Komplettlösung, um dies zu erreichen:
-- 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 [email protected]
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)
;
Wie wäre es damit:
ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'
Wobei die "300" eine beliebige Breite haben kann, unter Berücksichtigung der maximalen Anzahl von Elementen, von denen Sie denken, dass sie angezeigt werden.
Eine Möglichkeit, dies in SQL Server zu tun, besteht darin, den Tabelleninhalt als XML (für XML raw) zurückzugeben, das Ergebnis in eine Zeichenfolge zu konvertieren und die Tags durch "," zu ersetzen.
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
Tabellendefinition
CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;
Fügen wir nun Werte in diese Tabelle ein
INSERT INTO NAMES VALUES('PETER');
INSERT INTO NAMES VALUES('PAUL');
INSERT INTO NAMES VALUES('MARY');
Die Prozedur beginnt hier
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;
Ergebnis
PETER,PAUL,MARY
Obwohl es zu spät ist und bereits viele Lösungen hat. Hier ist eine einfache Lösung für 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 Sie können Folgendes versuchen:
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
Mit TABLE-Typ ist es extrem einfach. Stellen wir uns vor, Ihre Tabelle heißt Students
und hat die Spalte 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
Dieses Beispiel wurde in MS SQL Server 2008 R2 getestet
Mit einer rekursiven Abfrage können Sie dies tun:
-- 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
Es gibt noch ein paar weitere Möglichkeiten in 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
Wir können RECUSRSIVITY, WITH CTE, union ALL wie folgt verwenden
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
auf Chris Shaffer Antwort
wenn sich Ihre Daten wiederholen könnten
Tom
ALi
John
ALi
Tom
Mike
Anstatt Tom,ALi,John,ALi,Tom,Mike
zu haben
Sie können DISTINCT verwenden, um Duplikate zu vermeiden und Tom,ALi,John,Mike
zu erhalten.
DECLARE @Names VARCHAR(8000)
SELECT DISTINCT @Names = COALESCE(@Names + ',', '') + Name
FROM People
WHERE Name IS NOT NULL
SELECT @Names