SQL सर्वर में एक पाठ स्ट्रिंग में कई पंक्तियों से पाठ को कैसे संक्षिप्त करें?


1910

तीन पंक्तियों के साथ एक डेटाबेस तालिका नाम पर विचार करें:

Peter
Paul
Mary

क्या इसे एक ही तार में बदलने का एक आसान तरीका है Peter, Paul, Mary?


26
SQL सर्वर के लिए विशिष्ट उत्तरों के लिए, इस प्रश्न का प्रयास करें
मैट हैमिल्टन

17
MySQL के लिए, इस उत्तर से Group_Concat की जाँच करें
Pykler

26
काश SQL सर्वर के अगले संस्करण के लिए बहु-पंक्ति स्ट्रिंग संक्षेपण को हल करने के लिए एक नई सुविधा की पेशकश करेगा XML XML पथ की मूर्खता के बिना।
पीट एल्विन

4
एसक्यूएल नहीं है, लेकिन अगर यह एक बार की बात है, तो आप इस सूची को ब्राउज़र इन टूल टूल में बदल सकते हैं ।.town
Stack Man

3
ओरेकल में आप 11g r2 से LISTAGG (COLUMN_NAME) का उपयोग कर सकते हैं, इससे पहले WM_CONCAT (COLUMN_NAME) नामक एक असमर्थित फ़ंक्शन है जो ऐसा ही करता है।
रिचर्ड

जवाबों:


1431

यदि आप SQL Server 2017 या Azure पर हैं, तो Mathieu Renda उत्तर देखें

मेरे पास एक समान मुद्दा था जब मैं एक-से-कई रिश्तों के साथ दो तालिकाओं में शामिल होने की कोशिश कर रहा था। 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

13
महान समाधान। यदि आपको HTML में विशेष वर्णों को संभालने की आवश्यकता हो तो निम्नलिखित उपयोगी हो सकता है: Rob Farley: FOR XML PATH ('') के साथ विशेष वर्णों को संभालना

10
जाहिर है कि यह काम नहीं करता है अगर नामों में XML वर्ण होते हैं जैसे <या &। देखें @ बेनहिनमैन की टिप्पणी।
सैम

23
एनबी: यह विधि अनिर्धारित व्यवहार पर निर्भर है FOR XML PATH ('')। इसका मतलब है कि इसे विश्वसनीय नहीं माना जाना चाहिए क्योंकि कोई भी पैच या अपडेट इस कार्य को बदल सकता है। यह मूल रूप से एक पदावनत सुविधा पर निर्भर है।
बेकन बिट्स

26
@Whelkaholism नीचे पंक्ति यह है कि FOR XMLXML उत्पन्न करना है, न कि मनमाने तार। यही कारण है कि यह बच जाता है &, <और >एक्सएमएल इकाई कोड के लिए ( &amp;, &lt;, &gt;)। मुझे लगता है यह भी बच जाएगा "और 'करने के लिए &quot;और &apos;विशेषताओं में भी। यह है नहीं GROUP_CONCAT() , string_agg(), array_agg(), listagg(), आदि आप मेकअप की तरह यह ऐसा कर सकते हैं, भले ही। हमें अपना समय Microsoft द्वारा एक उचित कार्य को लागू करने की मांग करते हुए बिताना चाहिए
बेकन बिट्स

13
अच्छी खबर: MS SQL सर्वर string_aggv.Next में जुड़ जाएगा। और यह सब दूर जा सकते हैं।
जेसन सी

1008

यह उत्तर अप्रत्याशित परिणाम दे सकता है लगातार परिणामों के लिए, अन्य उत्तरों में विस्तृत XML XML पैट विधियों में से एक का उपयोग करें।

उपयोग करें COALESCE:

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

बस कुछ स्पष्टीकरण (चूंकि यह उत्तर अपेक्षाकृत नियमित रूप से प्राप्त होता है):

  • Coalesce वास्तव में सिर्फ एक उपयोगी धोखा है जो दो चीजों को पूरा करता है:

1) @Namesखाली स्ट्रिंग मान के साथ आरंभ करने की आवश्यकता नहीं है ।

2) अंत में एक अतिरिक्त विभाजक को अलग करने की आवश्यकता नहीं है।

  • उपरोक्त समाधान गलत परिणाम देगा यदि किसी पंक्ति का NULL नाम मान है (यदि कोई NULL है , तो NULL उस पंक्ति के बाद @Names NULL बना देगा , और अगली पंक्ति फिर से एक रिक्त स्ट्रिंग के रूप में शुरू होगी। आसानी से दो में से एक के साथ तय की गई है। समाधान:
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 को बदलें])।


72
स्पष्ट होने के लिए, सूची बनाने में कोलेस का कोई लेना-देना नहीं है, यह सिर्फ यह सुनिश्चित करता है कि NULL मान शामिल नहीं हैं।
ग्रीम पेरो

17
@ ग्रेम पेरो यह NULL मान को बाहर नहीं करता है (इसके लिए एक WHERE की आवश्यकता है - यह परिणाम खो देगा यदि इनपुट मानों में से एक NULL है), और इस दृष्टिकोण में इसकी आवश्यकता है क्योंकि: NULL + गैर-NULL - NULL और गैर-NULL + NULL -> NULL; यह भी @ डिफ़ॉल्ट रूप से NULL है और, वास्तव में, यह निर्धारित करने के लिए कि ',' जोड़ा जाना चाहिए या नहीं, यह पता लगाने के लिए संपत्ति का उपयोग यहाँ एक अंतर्निहित प्रहरी के रूप में किया जाता है।

62
कृपया ध्यान दें कि संघनन का यह तरीका SQL सर्वर पर किसी विशेष योजना के साथ क्वेरी को निष्पादित करने पर निर्भर करता है। मुझे इस विधि (ORDER BY के साथ) का उपयोग करके पकड़ा गया है। जब यह छोटी संख्या में पंक्तियों के साथ काम कर रहा था तो यह ठीक काम कर रहा था, लेकिन अधिक डेटा के साथ SQL सर्वर ने एक अलग योजना को चुना जिसके परिणामस्वरूप पहले आइटम का चयन किया गया, जिसमें कोई भी संगति नहीं थी।
अनीथ

17
इस पद्धति का चयन सूची में या उप-खंड के रूप में उप क्वेरी के रूप में नहीं किया जा सकता है, क्योंकि यह tSQL चर का उपयोग करता है। ऐसे मामलों में आप @Ritesh
R. Schreurs

11
यह सहमति का एक विश्वसनीय तरीका नहीं है। यह असमर्थित है और इसका उपयोग नहीं किया जाना चाहिए (प्रति Microsoft, उदाहरण के लिए support.microsoft.com/en-us/kb/287515 , connect.microsoft.com/SQLServer/Feedback/Details/704389 )। यह चेतावनी के बिना बदल सकता है। एक्सएमएल पथ तकनीक में चर्चा का प्रयोग करें stackoverflow.com/questions/5031204/... : मैं और अधिक यहाँ लिखा marc.durdin.net/2015/07/...
मार्क Durdin

453

SQL सर्वर 2017+ और SQL Azure: STRING_AGG

SQL सर्वर के अगले संस्करण के साथ शुरू, हम अंत में किसी भी चर या XML विचरी का सहारा लिए बिना पंक्तियों में समतल कर सकते हैं।

STRING_AGG (लेनदेन-एसक्यूएल)

बिना समूह के

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;

2
और, सीएलआर समाधानों के विपरीत, आपके पास छंटाई पर नियंत्रण है।
कैनन

STRING_AGG पर एक 4000 वर्ण प्रदर्शन सीमा लगती है
InspiredBy

वहाँ कोई रास्ता नहीं है के मामले में वहाँ है कोई समूह द्वारा (इसलिए "समूह के बिना" उदाहरण के लिए)?
रूदवेक

अद्यतन: मैं निम्नलिखित करने में कामयाब रहा, लेकिन क्या कोई साफ तरीका है? SELECT STRING_AGG (नाम, ',') AS विभागों से (SELECT TOP 100000 नाम FROM HumanResources.Department ORDER BY Name) D;
रूदवेक

362

XML data()MS SQL सर्वर में कमांड के माध्यम से एक विधि अभी तक नहीं दिखाई गई है:

मान लें कि NameList नामक एक कॉलम 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

15
पवित्र एस ** टी Thats अद्भुत! जब अपने आप निष्पादित किया जाता है, तो आपके उदाहरण के रूप में परिणाम हाइपरलिंक के रूप में स्वरूपित किया जाता है, कि जब क्लिक किया जाता है (एसएसएमएस में) डेटा युक्त एक नई विंडो खोलता है, लेकिन जब एक बड़ी क्वेरी के भाग के रूप में उपयोग किया जाता है तो यह केवल एक स्ट्रिंग के रूप में प्रकट होता है। क्या यह एक तार है? या यह xml है कि मुझे इस डेटा का उपयोग करने वाले एप्लिकेशन में अलग से इलाज करने की आवश्यकता है?
बेन

10
यह दृष्टिकोण XML <-> जैसे वर्णों से भी बच जाता है। इसलिए, '' <b> '+ FName +' </ b> 'का परिणाम "& l में; b & gt; जॉन & lt; / b & gt; & lt; b & gt; पॉल ..."
Lukhš Lánský

8
नीट समाधान। मैं यह देख रहा हूं कि जब मैं इसे नहीं + ', 'जोड़ता तब भी हर संघटित तत्व के बीच एक ही स्थान जोड़ता है।
बोडाद

8
@ बायोड वह सौदा का हिस्सा प्रतीत होता है। आप एक जोड़ा टोकन वर्ण पर प्रतिस्थापित करके वर्कअराउंड कर सकते हैं। उदाहरण के लिए, यह किसी भी लम्बाई के लिए एक सही अल्पविराम-सीमांकित सूची करता है:SELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
NReilingh

1
वाह, वास्तव में डेटा का उपयोग करके मेरे परीक्षण में () और एक प्रतिस्थापित नहीं की तुलना में अधिक प्रदर्शन है। सुपर अजीब।
NReilingh

306

में SQL सर्वर 2005

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

SQL सर्वर 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   abc@gmail.com
2   NULL
3   def@gmail.com, xyz@gmail.com

यह काम करेगा यहां तक ​​कि आपके डेटा में अमान्य XML वर्ण हैं

'"},{"_":"'सुरक्षित है क्योंकि अगर आप डेटा होते हैं '"},{"_":"',यह करने के लिए छोड़ दिया जाएगा"},{\"_\":\"

आप ', 'किसी भी स्ट्रिंग विभाजक के साथ बदल सकते हैं


और SQL Server 2017 में, Azure SQL डेटाबेस

आप नए STRING_AGG फ़ंक्शन का उपयोग कर सकते हैं


3
अग्रणी दो वर्णों को निक्स करने के लिए STUFF फ़ंक्शन का अच्छा उपयोग।
डेविड

3
मुझे यह समाधान सबसे अच्छा लगता है, क्योंकि मैं इसे 'लेबल के रूप में' जोड़कर आसानी से चुनिंदा सूची में उपयोग कर सकता हूं। मुझे यकीन नहीं है कि यह कैसे करना है @Ritesh के समाधान के साथ।
आर। श्रेयर्स

13
यह स्वीकार किए जाते हैं जवाब की तुलना में बेहतर है, क्योंकि इस विकल्प को भी इस तरह के रूप में संयुक्त राष्ट्र-भागने एक्सएमएल reserverd पात्रों को संभालती है <, >, &, आदि जो FOR XML PATH('')स्वचालित रूप से बच जाएंगे।
BateTech

यह एक भयानक प्रतिक्रिया है क्योंकि इसने इस मुद्दे को हल किया और एसक्यूएल के विभिन्न संस्करणों में चीजों को करने के सर्वोत्तम तरीके प्रदान करता है अब मैं चाहता हूं कि मैं 2017 / एज़्योर का उपयोग कर सकूं
क्रिस वार्ड

120

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

अच्छा काम करता है। लेकिन जब मैं उपयोग करता SEPARATOR '", "'हूं तो अंतिम प्रविष्टि के अंत में कुछ चार्ट याद करूंगा। ऐसा क्यों हो सकता है?
गोलूमेव २ go'१६

@gooleem आपका क्या मतलब है इस पर मैं स्पष्ट नहीं हूं, लेकिन यह फ़ंक्शन केवल विभाजकों को आइटम के बीच रखता है, बाद में नहीं। यदि वह उत्तर नहीं है, तो मैं एक नया प्रश्न पोस्ट करने की सलाह दूंगा।
डैरिल हेन

मेरी जरूरतों के लिए @DarrylHein मैंने ऊपर के रूप में विभाजक का उपयोग किया। लेकिन यह मुझे आउटपुट के बहुत अंत में कुछ चार्ट में कटौती करता है। यह बहुत अजीब है और एक बग प्रतीत होता है। मेरे पास कोई हल नहीं है, मैं सिर्फ काम करता हूं।
गोलेमेम

मूल रूप से काम करता है। दो बातों पर विचार करने के लिए: 1) यदि आपके स्तंभ एक नहीं है CHAR, तो आप इसे कास्ट करने के लिए की जरूरत है, उदाहरण के लिए के माध्यम से GROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')2) यदि आप कई मूल्यों आ रहा है, तो आप वृद्धि करनी चाहिए group_concat_max_lenके रूप में में लिखा stackoverflow.com/a/1278210/1498405
hardmooth

58

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

2
यह वास्तव में सबसे अच्छा समाधान आईएमओ है क्योंकि यह XML प्रस्तुत करने वाले एन्कोडिंग मुद्दों से बचा जाता है। मैंने इस्तेमाल किया Declare @Numbers AS Nvarchar(MAX)और यह ठीक काम किया। क्या आप बता सकते हैं कि आप कृपया इसका उपयोग न करने की सलाह क्यों देते हैं?
EvilDr

7
यह समाधान 8 साल पहले ही पोस्ट किया जा चुका है! stackoverflow.com/a/194887/986862
आंद्रे फिग्यूएरेडो

ये क्वेरी क्यों लौट रही है ??? सिरिलिक के बजाय प्रतीकों? क्या यह सिर्फ आउटपुट इश्यू है?
अकमल सालिकोव

48

Postgres arrays कमाल की हैं। उदाहरण:

कुछ परीक्षण डेटा बनाएँ:

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 के बाद से यह और भी आसान है


यदि आपको एक से अधिक कॉलम की आवश्यकता होती है, उदाहरण के लिए कोष्ठक में उनके कर्मचारी आईडी, कॉनैट ऑपरेटर का उपयोग करते हैं: select array_to_string(array_agg(name||'('||id||')'
रिचर्ड फॉक्स


46

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 वर्णों पर जाने से रोकता है।


1
Oracle के पुराने संस्करणों के लिए, wm_concat एकदम सही है। इसका उपयोग एलेक्स द्वारा लिंक उपहार में समझाया गया है। एलेक्स!
टस्कनेली २०'१५

LISTAGGसही काम करता है! बस यहां से जुड़े दस्तावेज़ पढ़ें। wm_concatसंस्करण 12c बाद से हटा दिया गया।
asgs

34

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

2
मेरा मानना ​​है कि यह विफल रहता है जब मान XML प्रतीकों जैसे <या &
सैम

28

मेरे पास घर पर SQL सर्वर तक पहुंच नहीं है, इसलिए मुझे यहाँ सिंटैक्स पर अनुमान है, लेकिन यह अधिक या कम है:

DECLARE @names VARCHAR(500)

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

11
आपको कुछ गैर-अशक्त के लिए inn @names की आवश्यकता होगी, अन्यथा आपको NULL भर में मिलेगा; आप भी (अनावश्यक एक सहित) सीमांकक को संभालने के लिए आवश्यकता होगी
मार्क Gravell

3
इस दृष्टिकोण के साथ एकमात्र समस्या (जो मैं हर समय उपयोग करता हूं) यह है कि आप इसे एम्बेड नहीं कर सकते हैं
ekkis

1
अग्रणी स्थान से छुटकारा पाने के लिए क्वेरी को बदल देंSELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
तिआन वैन हीरडेन

इसके अलावा, आपको यह जांचना होगा कि नाम अशक्त नहीं है, आप इसे करके कर सकते हैं:SELECT @names = @names + ISNULL(' ' + Name, '')
Vita1ij

28

एक पुनरावर्ती 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

1
फ्लैबगैन्ड के लिए: यह क्वेरी 12 पंक्तियों (एक 3 कॉलम) को एक अस्थायी आधार पर सम्मिलित करती है, फिर एक पुनरावर्ती कॉमन टेबल एक्सप्रेशन (rCTE) बनाता है और फिर name कॉलम को कॉमा से अलग किए गए स्ट्रिंग में s के 4 समूहों के लिए समतल करता है id। पहली नज़र में, मुझे लगता है कि यह एसक्यूएल सर्वर के लिए अन्य समाधानों की तुलना में अधिक काम है।
knb

2
@ एकब: यकीन नहीं है कि अगर प्रशंसा, निंदा या सिर्फ आश्चर्य है। आधार तालिका इसलिए है क्योंकि मुझे वास्तव में काम करने के लिए मेरे उदाहरण पसंद हैं, यह वास्तव में सवाल के साथ कुछ भी नहीं है।
जोर्मेनो

26

आपको एक वैरिएबल बनाने की आवश्यकता है जो आपके अंतिम परिणाम को पकड़ेगा और उसमें चयन करेगा, जैसे।

सबसे आसान समाधान

DECLARE @char VARCHAR(MAX);

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

PRINT @char;

25

PostgreSQL 9.0 के साथ शुरू करना यह काफी सरल है:

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

9.0 से पहले के संस्करणों array_agg()में hgmnz द्वारा दिखाया जा सकता है


कॉलम के साथ ऐसा करने के लिए, जो टाइप टेक्स्ट के नहीं हैं, आपको एक टाइप कास्ट जोड़ने की जरूरत है:SELECT string_agg(non_text_type::text, ',') FROM table
तोरबेन कोहलमीयर

@TorbenKohlmeier: आपको केवल गैर-वर्ण कॉलम (जैसे पूर्णांक, दशमलव) के लिए चाहिए। यह ठीक काम करता है varcharया इसके लिएchar
a_horse_with_no_name


18

XML का उपयोग करने से मुझे कॉमा के साथ पंक्तियों को अलग करने में मदद मिली। अतिरिक्त अल्पविराम के लिए हम SQL सर्वर के बदले हुए फ़ंक्शन का उपयोग कर सकते हैं। अल्पविराम जोड़ने के बजाय, एएस 'डेटा ()' के उपयोग से पंक्तियों को रिक्त स्थान के साथ बदल दिया जाएगा, जिसे बाद में अल्पविराम से प्रतिस्थापित किया जा सकता है, जैसा कि नीचे लिखा गया वाक्यविन्यास है।

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 

2
यह मेरे लिए सबसे अच्छा जवाब है। जब आपको किसी अन्य तालिका में शामिल होने की आवश्यकता होती है, तो घोषित चर का उपयोग अच्छा नहीं होता है और यह अच्छा और छोटा होता है। अच्छा कार्य।
डेविड रौसेल

7
यदि FName डेटा में पहले से ही रिक्त स्थान है, तो यह अच्छा नहीं है, उदाहरण के लिए "My Name"
binball

वास्तव में यह मेरे लिए ms-sql 2016 पर काम कर रहा है। ब्रांड के आईडी कहां से (IN (1,2,3,4) xml पथ ('')), '', '' के लिए REPLACE ((नाम के रूप में नाम चुनें) का चयन करें। , ') ऑल ब्रैंड्स के रूप में
रेजवानुल रजा

17

कोई अतिरिक्त अल्पविराम के साथ एक तैयार-से-उपयोग समाधान:

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

खाली सूची के परिणामस्वरूप NULL मान प्राप्त होगा। आमतौर पर आप सूची को एक टेबल कॉलम या प्रोग्राम चर में डालेंगे: 255 अधिकतम लंबाई को अपनी आवश्यकता के अनुसार समायोजित करें।

(दिवाकर और जेन्स फ्रांसेन ने अच्छे जवाब दिए, लेकिन सुधार की जरूरत है।)


इस का उपयोग करते समय अल्पविराम से पहले एक स्थान है :(
slayernoah

1
बस की जगह ', 'के साथ ','अगर आप अतिरिक्त जगह नहीं करना चाहती।
डैनियल रीस

13
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

10
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

यह शुरुआत में आवारा अल्पविराम डालता है।

हालाँकि, यदि आपको अन्य कॉलमों की आवश्यकता है, या CSV को एक चाइल्ड टेबल चाहिए, तो आपको इसे स्केलर यूजर डिफाइन्ड फील्ड (UDF) में लपेटना होगा।

आप XML पथ का चयन खंड में सहसंबद्ध उपश्रेणी के रूप में भी कर सकते हैं (लेकिन मुझे तब तक इंतजार करना होगा जब तक मैं काम पर वापस नहीं जाता क्योंकि Google घर पर काम का सामान नहीं करता है :-)


10

अन्य उत्तरों के साथ, उत्तर पढ़ने वाले व्यक्ति को किसी विशिष्ट डोमेन तालिका जैसे वाहन या छात्र के बारे में पता होना चाहिए। समाधान का परीक्षण करने के लिए तालिका को डेटा के साथ बनाया और आबाद किया जाना चाहिए।

नीचे एक उदाहरण है जो SQL सर्वर "Information_Schema.Columns" तालिका का उपयोग करता है। इस समाधान का उपयोग करके, कोई तालिका बनाने या डेटा जोड़े जाने की आवश्यकता नहीं है। यह उदाहरण डेटाबेस में सभी तालिकाओं के लिए स्तंभ नामों की अल्पविराम से अलग सूची बनाता है।

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 

7

ओरेकल डीबी के लिए, इस प्रश्न को देखें: स्टोर की गई प्रक्रिया बनाए बिना ओरेकल में एक में कई पंक्तियों को कैसे समेटा जा सकता है?

सबसे अच्छा जवाब @Emmanuel द्वारा बनाया गया प्रतीत होता है, जो Oracle 11g रिलीज़ 2 और बाद में उपलब्ध अंतर्निहित LISTAGG () फ़ंक्शन का उपयोग करता है।

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 दस्तावेज़ में यह करने के लिए एक गाइड है।


7

शून्य मानों से बचने के लिए आप CONCAT का उपयोग कर सकते हैं ()

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

यह जानना अच्छा होगा कि कॉनकैट क्यों काम करता है। MSDN के लिए एक लिंक अच्छा होगा।
उल्टा इंजीनियर

7

मुझे वास्तव में दाना के जवाब की पसंद थी । बस इसे पूरा करना चाहते थे।

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

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

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

यदि आप अंतिम दो प्रतीकों ',' को हटा रहे हैं, तो आपको नाम के बाद '(' का चयन करने की आवश्यकता है '(' SELECT \ @names = \ @names + Name + ',' FROM Names ')। इस तरह अंतिम दो वर्ण हमेशा ',' होंगे।
JT_

मेरे मामले में मुझे अग्रणी अल्पविराम से छुटकारा पाने की आवश्यकता थी इसलिए क्वेरी को बदल दें, SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Namesफिर आपको इसे बाद में छोटा नहीं करना होगा।
तियान वान हीरडेन

6

इस जवाब को काम करने के लिए सर्वर में कुछ विशेषाधिकार की आवश्यकता होगी।

असेंबली आपके लिए एक अच्छा विकल्प है। बहुत सारी साइटें हैं जो बताती हैं कि इसे कैसे बनाया जाए। एक मुझे लगता है कि बहुत अच्छी तरह से समझाया गया है यह है एक

यदि आप चाहते हैं, तो मैं पहले ही विधानसभा बना चुका हूं, और यहां DLL डाउनलोड करना संभव है

एक बार जब आप इसे डाउनलोड कर लेते हैं, तो आपको अपने SQL सर्वर में निम्न स्क्रिप्ट को चलाने की आवश्यकता होगी:

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

आशा है ये मदद करेगा!!!


1
DLL लिंक 404 त्रुटि है। इसके लिए एक विधानसभा का उपयोग करना ओवरकिल है। SQL सर्वर के लिए सर्वश्रेष्ठ उत्तर देखें ।
संरक्षित

6

MySQL पूरा उदाहरण:

हमारे पास ऐसे उपयोगकर्ता हैं जिनके पास कई डेटा हो सकते हैं और हम एक आउटपुट रखना चाहते हैं, जहां हम सभी उपयोगकर्ताओं को एक सूची में डाटास देख सकते हैं:

परिणाम:

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

मैं आमतौर पर एसक्यूएल सर्वर में तारों को छिपाने के लिए इस तरह का चयन करता हूं:

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

यदि आप नल से निपटना चाहते हैं, तो आप इसे एक क्लॉज जोड़कर कर सकते हैं या पहले वाले के आसपास एक और COALESCE जोड़ सकते हैं।

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

5

यह मेरे लिए काम किया ( SqlServer 2016 ):

SELECT CarNamesString = STUFF((
         SELECT ',' + [Name]
            FROM tbl_cars 
            FOR XML PATH('')
         ), 1, 1, '')

यहाँ स्रोत है: https://www.mytecbits.com/

और MySql के लिए एक समाधान (चूंकि यह पृष्ठ MySql के लिए Google में दिखाया गया है)

SELECT [Name],
       GROUP_CONCAT(DISTINCT [Name]  SEPARATOR ',')
       FROM tbl_cars

से MySql प्रलेखन



4

यह उपयोगी भी हो सकता है

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

5
दुर्भाग्य से यह व्यवहार आधिकारिक रूप से समर्थित नहीं है। MSDN कहता है: "यदि किसी चर का चयन किसी सूची में किया जाता है, तो उसे स्केलर मान दिया जाना चाहिए या SELECT स्टेटमेंट को केवल एक पंक्ति में वापस करना चाहिए।" और ऐसे लोग हैं जो समस्याओं का अवलोकन करते हैं: sqlmag.com/sql-server/multi-row-variable-assignment-and-order
विस्फोट करना
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.