it-swarm.asia

كيفية ربط النص من صفوف متعددة في سلسلة نصية واحدة في خادم SQL؟

اطلع على جدول قاعدة بيانات به أسماء ، مع ثلاثة صفوف:

Peter
Paul
Mary

هل هناك طريقة سهلة لتحويل هذا إلى سلسلة واحدة من Peter, Paul, Mary؟

1687
JohnnyM

إذا كنت تستخدم 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
1247
Ritesh

هذه الإجابة قد ترجع نتائج غير متوقعة للحصول على نتائج متسقة ، استخدم إحدى طرق FOR XML PATH المفصلة في الإجابات الأخرى.

استخدم COALESCE:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name 
FROM People

فقط بعض التفسير (نظرًا لأن هذا الجواب يبدو أنه يحصل على آراء منتظمة نسبيًا):

  • Coalesce هو مجرد خداع مفيد يحقق شيئين:

1) لا حاجة لتهيئة @Names بقيمة سلسلة فارغة.

2) لا حاجة لتجريد فاصل إضافي في النهاية.

  • الحل المذكور أعلاه سوف يعطي نتائج غير صحيحة إذا كان للصف (_ null _ قيمة الاسم (إذا كان هناك NULL ، فإن {NULL سيجعل @NamesNULL بعد هذا الصف ، وسيبدأ الصف التالي من جديد كسلسلة فارغة مرة أخرى. تم إصلاحه بسهولة باستخدام أحد الحلين التاليين:
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 s ، الخيار الثاني يبقيهم في القائمة برسالة علامة [استبدل "N/A" بأي شيء مناسب لك]) .

945
Chris Shaffer

إحدى الطرق التي لم تظهر بعد عبر الأمر XMLdata() في MS SQL Server هي:

تفترض جدول يسمى قائمة الاسم مع عمود واحد يسمى FName ،

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
332
jens frandsen

SQL Server 2017+ و SQL Azure: STRING_AGG

بدءًا من الإصدار التالي من SQL Server ، يمكننا أخيرًا تسلسل عبر الصفوف دون الحاجة إلى اللجوء إلى أي متغير أو XML witchery.

STRING_AGG (Transact-SQL)

بدون تجميع

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;
282
Mathieu Renda

في SQL Server 2005

SELECT Stuff(
  (SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'')

في SQL Server 2016

يمكنك استخدام بناء جملة 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   [email protected]
2   NULL
3   [email protected], [email protected]

سيعمل هذا حتى تحتوي بياناتك على أحرف XML غير صالحة

رمز '"},{"_":"' آمن لأنه إذا كانت بياناتك تحتوي على '"},{"_":"', فسيتم تجاوزه إلى "},{\"_\":\"

يمكنك استبدال ', ' بأي فاصل سلسلة


وفي SQL Server 2017 ، قاعدة بيانات SQL Azure

يمكنك استخدام الوظيفة الجديدة STRING_AGG

266
Steven Chong

في 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
111
Darryl Hein

استخدم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
54
pedram

صفائف بوستجرس رائعة. مثال:

إنشاء بعض بيانات الاختبار:

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 هو أسهل .

47
hgmnz

يدعم Oracle 11g الإصدار 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 حرف.

45
Alex

في 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
33
Yogesh Bhadauirya

ليس لدي إمكانية الوصول إلى SQL Server في المنزل ، لذلك أعتقد في بناء الجملة هنا ، لكنه أكثر أو أقل:

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names
26
Dana

تحتاج إلى إنشاء متغير يحتفظ بالنتيجة النهائية وتحديدها ، مثل ذلك.

الحل الأسهل

DECLARE @char VARCHAR(MAX);

SELECT @char = COALESCE(@char + ', ' + [column], [column]) 
FROM [table];

PRINT @char;
25
Tigerjz32

تم اقتراح حل 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
24
jmoreno

بدءاً من PostgreSQL 9.0 ، هذا بسيط جدًا:

select string_agg(name, ',') 
from names;

في الإصدارات قبل 9.0 array_agg() يمكن استخدامها كما هو موضح بواسطة hgmnz

23
a_horse_with_no_name

في SQL Server vNext ، سيتم إنشاء هذا باستخدام دالة STRING_AGG ، اقرأ المزيد عنها هنا: https://msdn.Microsoft.com/en-us/library/mt790580.aspx

21
Henrik Fransas

حل جاهز للاستخدام ، بدون فواصل إضافية:

select substring(
        (select ', '+Name AS 'data()' from Names for xml path(''))
       ,3, 255) as "MyList"

قائمة فارغة سيؤدي إلى قيمة فارغة. عادةً ستقوم بإدراج القائمة في عمود الجدول أو متغير البرنامج: اضبط الحد الأقصى لطول 255 حسب حاجتك.

(قدم ديواكر وجينس فراندسن إجابات جيدة ، لكنهما بحاجة إلى تحسين).

17
Daniel Reis

ساعدني استخدام XML في فصل الصفوف بفواصل. بالنسبة للفاصلة الإضافية ، يمكننا استخدام وظيفة الاستبدال في SQL Server. بدلاً من إضافة فاصلة ، سيؤدي استخدام AS "data ()" إلى ربط الصفوف بمسافات ، والتي يمكن استبدالها لاحقًا بفواصل مثل بناء الجملة المكتوب أدناه.

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 
17
Diwakar
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')

إليك عينة:

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
12
Max Szczurek
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

هذا يضع الفاصلة الضالة في البداية.

ومع ذلك ، إذا كنت بحاجة إلى أعمدة أخرى ، أو إلى CSV جدولًا فرعيًا ، فستحتاج إلى التفاف هذا في حقل معرف مستخدم (UDF).

يمكنك استخدام مسار XML ك استعلام فرعي مرتبط في جملة SELECT أيضًا (لكن يجب أن أنتظر حتى أعود إلى العمل لأن Google لا تعمل أشياء في المنزل :-)

10
gbn

مع الإجابات الأخرى ، يجب أن يكون الشخص الذي يقرأ الإجابة على دراية بجدول مجال معين مثل السيارة أو الطالب. يجب إنشاء الجدول وتعبئته بالبيانات لاختبار حل.

يوجد أدناه مثال يستخدم جدول "Information_Schema.Columns" لـ SQL Server. باستخدام هذا الحل ، لا يلزم إنشاء جداول أو إضافة بيانات. ينشئ هذا المثال قائمة بأسماء الأعمدة مفصولة بفواصل لجميع الجداول في قاعدة البيانات.

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 
9
Mike Barlow - BarDev

بالنسبة لقواعد بيانات Oracle ، راجع هذا السؤال: كيف يمكن تجميع صفوف متعددة في واحد في Oracle دون إنشاء إجراء مخزن؟

يبدو أن أفضل إجابة هي بواسطةEmmanuel ، باستخدام وظيفة LISTAGG () المدمجة ، والمتاحة في Oracle 11g الإصدار 2 والإصدارات الأحدث.

SELECT question_id,
   LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id

كما أشار @ user762952 ، ووفقًا لوثائق Oracle http://www.Oracle-base.com/articles/misc/string-aggregation-techniques.php ، فإن وظيفة WM_CONCAT () هي أيضًا خيار. يبدو مستقرًا ، لكن Oracle يوصي صراحة بعدم استخدامه لأي تطبيق SQL ، لذا استخدم على مسؤوليتك الخاصة.

بخلاف ذلك ، سوف تضطر إلى كتابة وظيفتك الخاصة ؛ يحتوي مستند Oracle أعلاه على دليل حول كيفية القيام بذلك.

7
ZeroK

أنا حقا أحب أناقة جواب دانا . أردت فقط أن تكمله.

DECLARE @names VARCHAR(MAX)
SET @names = ''

SELECT @names = @names + ', ' + Name FROM Names 

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
7
Oleg Sakharov

لتجنب القيم الخالية ، يمكنك استخدام CONCAT ()

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names
6
Rapunzo

ستتطلب هذه الإجابة بعض الامتيازات في الخادم للعمل.

الجمعيات هي خيار جيد بالنسبة لك. هناك الكثير من المواقع التي تشرح كيفية إنشائها. الشخص الذي أعتقد أنه موضح جيدًا هو هذا واحد

إذا كنت تريد ، لقد قمت بالفعل بإنشاء التجميع ، ويمكن تنزيل 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

آمل أن يساعد!

6
Nizam

أنا عادة ما تستخدم اختيار مثل هذا لسلاسل السلاسل في 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
5
Vladimir Nesterovsky

MySQL Complete مثال:

لدينا مستخدمون يمكنهم الحصول على العديد من البيانات ونريد الحصول على ناتج ، حيث يمكننا رؤية جميع المستخدمين Datas في قائمة:

نتيجة:

___________________________
| 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
5
user1767754

إذا كنت ترغب في التعامل مع القيم الخالية ، فيمكنك القيام بذلك عن طريق إضافة جملة مكان أو إضافة تحديث آخر حول الأول.

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
5
Pramod

هذا يمكن أن يكون مفيدا للغاية

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
4
endo64

في Oracle ، يكون wm_concat. أعتقد أن هذه الوظيفة متوفرة في إصدار 10g وأعلى.

4
user762952

تنطبق هذه الطريقة على قاعدة بيانات Teradata Aster فقط لأنها تستخدم وظيفة NPATH الخاصة بها.

مرة أخرى ، لدينا طلاب الجدول

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

ثم مع NPATH هو مجرد اختيار واحد:

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
  )
);

نتيجة:

SubjectID       StudentName
----------      -------------
1               [John, Mary, Sam]
2               [Alaina, Edward]
3
topchef

لم أقم بإجراء أي تحليل للأداء حيث أن قائمتي تحتوي على أقل من 10 عناصر ، لكني اندهشت بعد الاطلاع على الإجابات الثلاثين التي لا تزال لدي إجابة على إجابة مماثلة تم تقديمها بالفعل مماثلة لاستخدام COALESCE لقائمة مجموعة واحدة ولم لا يلزم حتى تعيين المتغير الخاص بي (الإعدادات الافتراضية إلى NULL على أي حال) ويفترض أن جميع الإدخالات في جدول البيانات المصدر الخاص بي غير فارغة:

DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData

أنا متأكد من أن COALESCE يستخدم داخليًا نفس الفكرة. دعونا نأمل MS لا يغير هذا علي.

3
Glen

إليك الحل الكامل لتحقيق هذا:

-- 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) 
3
Ravi Pipaliya

- خادم SQL 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)
;
3
Graeme

وماذا عن هذا:

   ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'

حيث يمكن أن يكون "300" بأي عرض مع الأخذ في الاعتبار الحد الأقصى لعدد العناصر التي تعتقد أنها ستظهر.

2
Hans Bluh

إحدى الطرق التي يمكنك القيام بها في SQL Server هي إرجاع محتوى الجدول كـ XML (لـ XML raw) ، وتحويل النتيجة إلى سلسلة ثم استبدال العلامات بـ "،".

2
Manu

@ User1460901 يمكنك تجربة شيء مثل هذا:

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
1
Aura
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
1
Muhammad Bilal

يوجد أدناه إجراء PL/SQL بسيط لتنفيذ السيناريو المحدد باستخدام "حلقة أساسية" و "rownum"

تعريف الجدول

CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;

دعنا ندرج القيم في هذا الجدول

INSERT INTO NAMES VALUES('PETER');
INSERT INTO NAMES VALUES('PAUL');
INSERT INTO NAMES VALUES('MARY');

يبدأ الإجراء من هنا

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;

نتيجة

PETER,PAUL,MARY
1
Pooja Bhat

مع نوع TABLE فمن السهل للغاية. دعنا نتخيل أن الجدول الخاص بك يسمى Students وله عمود 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

تم اختبار هذا المثال في MS SQL Server 2008 R2

1
Max Tkachenko

على الرغم من فوات الأوان ، ولديه بالفعل العديد من الحلول. هنا حل بسيط لماي:

SELECT t1.id,
        GROUP_CONCAT(t1.id) ids
 FROM table t1 JOIN table t2 ON (t1.id = t2.id)
 GROUP BY t1.id
1
Shahbaz

باستخدام استعلام تكراري ، يمكنك القيام بذلك:

-- 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
1
Esperento57

هناك عدة طرق أخرى في 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
1
Priti Getkewar Joshi

يمكننا استخدام RECUSRSIVITY ، مع CTE ، اتحاد ALL على النحو التالي

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
0
Kemal AL GAZZAH