मुझे कैसे मिलेगा:
id Name Value
1 A 4
1 B 8
2 C 9
सेवा
id Column
1 A:4, B:8
2 C:9
मुझे कैसे मिलेगा:
id Name Value
1 A 4
1 B 8
2 C 9
सेवा
id Column
1 A:4, B:8
2 C:9
जवाबों:
कोई कोरियर, लूप लूप, या उपयोगकर्ता-परिभाषित फ़ंक्शन की आवश्यकता नहीं है ।
बस XML और PATH के लिए रचनात्मक होना चाहिए।
[नोट: यह समाधान केवल SQL 2005 और बाद में काम करता है। मूल प्रश्न उपयोग में संस्करण को निर्दिष्ट नहीं करता है।]
CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT
[ID],
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
यदि यह SQL सर्वर 2017 या SQL सर्वर Vnext, SQL Azure है तो आप नीचे के रूप में string_agg का उपयोग कर सकते हैं:
select id, string_agg(concat(name, ':', [value]), ', ')
from #YourTable
group by id
XML पथ का उपयोग पूरी तरह से नहीं किया जाएगा जैसा कि आप उम्मीद कर सकते हैं ... यह "&" को "& amp;" से बदल देगा और भी गड़बड़ करेगा <" and ">
... शायद कुछ और चीजें, निश्चित नहीं ... लेकिन आप यह कोशिश कर सकते हैं
मुझे इसके लिए वर्कअराउंड आया ... आपको बदलने की आवश्यकता है:
FOR XML PATH('')
)
साथ में:
FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')
... या NVARCHAR(MAX)
यदि आप का उपयोग कर रहे हैं कि क्या thats।
क्यों नरक SQL
एक समवर्ती कुल कार्य नहीं है? यह एक PITA है।
जब मैं तार रिक्त स्थान और विशेष एक्सएमएल वर्ण (युक्त साथ काम करने के लिए केविन फेयरचाइल्ड के सुझाव को परिवर्तित करने की कोशिश की मैं समस्याओं के एक जोड़े में भाग &
, <
, >
) जो इनकोडिंग किया गया।
मेरे कोड का अंतिम संस्करण (जो मूल प्रश्न का उत्तर नहीं देता है लेकिन किसी के लिए उपयोगी हो सकता है) इस तरह दिखता है:
CREATE TABLE #YourTable ([ID] INT, [Name] VARCHAR(MAX), [Value] INT)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'Oranges & Lemons',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'1 < 2',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
SELECT [ID],
STUFF((
SELECT ', ' + CAST([Name] AS VARCHAR(MAX))
FROM #YourTable WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE
/* Use .value to uncomment XML entities e.g. > < etc*/
).value('.','VARCHAR(MAX)')
,1,2,'') as NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
एक स्थान को एक सीमांकक के रूप में उपयोग करने के बजाय और सभी रिक्त स्थान को कॉमा के साथ बदलने के बजाय, यह सिर्फ प्रत्येक मान के लिए एक अल्पविराम और स्थान को पूर्व-लंबित करता STUFF
है, फिर पहले दो वर्णों को निकालने के लिए उपयोग करता है।
TYPE निर्देश का उपयोग करके XML एन्कोडिंग का स्वचालित रूप से ध्यान रखा जाता है ।
Sql Server 2005 और इसके बाद के संस्करण का उपयोग कर एक अन्य विकल्प
---- test data
declare @t table (OUTPUTID int, SCHME varchar(10), DESCR varchar(10))
insert @t select 1125439 ,'CKT','Approved'
insert @t select 1125439 ,'RENO','Approved'
insert @t select 1134691 ,'CKT','Approved'
insert @t select 1134691 ,'RENO','Approved'
insert @t select 1134691 ,'pn','Approved'
---- actual query
;with cte(outputid,combined,rn)
as
(
select outputid, SCHME + ' ('+DESCR+')', rn=ROW_NUMBER() over (PARTITION by outputid order by schme, descr)
from @t
)
,cte2(outputid,finalstatus,rn)
as
(
select OUTPUTID, convert(varchar(max),combined), 1 from cte where rn=1
union all
select cte2.outputid, convert(varchar(max),cte2.finalstatus+', '+cte.combined), cte2.rn+1
from cte2
inner join cte on cte.OUTPUTID = cte2.outputid and cte.rn=cte2.rn+1
)
select outputid, MAX(finalstatus) from cte2 group by outputid
SQLCLR एग्रीगेट्स को http://groupconcat.codeplex.com से इंस्टॉल करें
फिर आप इस तरह से कोड लिख सकते हैं ताकि आपके द्वारा मांगे गए परिणाम प्राप्त हो सकें:
CREATE TABLE foo
(
id INT,
name CHAR(1),
Value CHAR(1)
);
INSERT INTO dbo.foo
(id, name, Value)
VALUES (1, 'A', '4'),
(1, 'B', '8'),
(2, 'C', '9');
SELECT id,
dbo.GROUP_CONCAT(name + ':' + Value) AS [Column]
FROM dbo.foo
GROUP BY id;
एसक्यूएल सर्वर 2005 और बाद में आपको अपने स्वयं के कस्टम कुल कार्यों को बनाने की अनुमति देता है , जिसमें समंजन जैसी चीजें शामिल हैं- लिंक किए गए लेख के तल पर नमूना देखें।
आठ साल बाद ... Microsoft SQL सर्वर vNext डेटाबेस इंजन ने अंत में समूहीकृत स्ट्रिंग संघनन का सीधे समर्थन करने के लिए Transact-SQL बढ़ाया है। सामुदायिक तकनीकी पूर्वावलोकन संस्करण 1.0 ने STRING_AGG फ़ंक्शन को जोड़ा और CTP 1.1 ने STRING_AGG फ़ंक्शन के लिए withIN GROUP क्लॉज़ जोड़ा।
संदर्भ: https://msdn.microsoft.com/en-us/library/mt775028.aspx
यह केविन फेयरचाइल्ड की पोस्ट के लिए एक अतिरिक्त है (वैसे बहुत चालाक)। मैंने इसे एक टिप्पणी के रूप में जोड़ा होगा, लेकिन मेरे पास अभी पर्याप्त बिंदु नहीं हैं :)
मैं इस विचार का उपयोग उस दृश्य के लिए कर रहा था जिस पर मैं काम कर रहा था, हालाँकि जिन वस्तुओं में मैं समाहित था, वे रिक्त स्थान समेट रहे थे। इसलिए मैंने सीमांकक के रूप में रिक्त स्थान का उपयोग न करने के लिए कोड को थोड़ा संशोधित किया।
फिर से शांत केविन धन्यवाद केविन के लिए!
CREATE TABLE #YourTable ( [ID] INT, [Name] CHAR(1), [Value] INT )
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'A', 4)
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'B', 8)
INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (2, 'C', 9)
SELECT [ID],
REPLACE(REPLACE(REPLACE(
(SELECT [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) as A
FROM #YourTable
WHERE ( ID = Results.ID )
FOR XML PATH (''))
, '</A><A>', ', ')
,'<A>','')
,'</A>','') AS NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
Oracle में आप LISTAGG कुल फ़ंक्शन का उपयोग कर सकते हैं।
मूल अभिलेख
name type
------------
name1 type1
name2 type2
name2 type3
Sql
SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name
परिणाम होना
name type
------------
name1 type1
name2 type2; type3
इस तरह का प्रश्न यहाँ बहुत बार पूछा जाता है, और समाधान अंतर्निहित आवश्यकताओं पर बहुत कुछ निर्भर करता है:
https://stackoverflow.com/search?q=sql+pivot
तथा
https://stackoverflow.com/search?q=sql+concatenate
आमतौर पर, गतिशील SQL, उपयोगकर्ता द्वारा परिभाषित फ़ंक्शन, या कर्सर के बिना ऐसा करने का कोई SQL-एकमात्र तरीका नहीं है।
बस कैड ने जो कहा, उसे जोड़ने के लिए, यह आमतौर पर एक फ्रंट-एंड डिस्प्ले चीज़ है और इसलिए इसे वहाँ संभाला जाना चाहिए। मुझे पता है कि कभी-कभी फ़ाइल निर्यात या अन्य "एसक्यूएल केवल" समाधान जैसी चीजों के लिए एसक्यूएल में कुछ 100% लिखना आसान होता है, लेकिन अधिकांश बार इस कॉनसेप्टेशन को आपके डिस्प्ले लेयर में संभाला जाना चाहिए।
एक कर्सर की जरूरत नहीं है ... कुछ समय के लिए पर्याप्त है।
------------------------------
-- Setup
------------------------------
DECLARE @Source TABLE
(
id int,
Name varchar(30),
Value int
)
DECLARE @Target TABLE
(
id int,
Result varchar(max)
)
INSERT INTO @Source(id, Name, Value) SELECT 1, 'A', 4
INSERT INTO @Source(id, Name, Value) SELECT 1, 'B', 8
INSERT INTO @Source(id, Name, Value) SELECT 2, 'C', 9
------------------------------
-- Technique
------------------------------
INSERT INTO @Target (id)
SELECT id
FROM @Source
GROUP BY id
DECLARE @id int, @Result varchar(max)
SET @id = (SELECT MIN(id) FROM @Target)
WHILE @id is not null
BEGIN
SET @Result = null
SELECT @Result =
CASE
WHEN @Result is null
THEN ''
ELSE @Result + ', '
END + s.Name + ':' + convert(varchar(30),s.Value)
FROM @Source s
WHERE id = @id
UPDATE @Target
SET Result = @Result
WHERE id = @id
SET @id = (SELECT MIN(id) FROM @Target WHERE @id < id)
END
SELECT *
FROM @Target
चलो बहुत सरल हो जाओ:
SELECT stuff(
(
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
FOR XML PATH('')
)
, 1, 2, '')
इस पंक्ति को बदलें:
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
आपकी क्वेरी के साथ
किसी भी क्रॉस अप्लाई के उत्तर को नहीं देखा, एक्सएमएल निष्कर्षण की भी कोई आवश्यकता नहीं है। यहाँ केविन फेयरचाइल्ड ने जो लिखा है उसका थोड़ा अलग संस्करण है। अधिक जटिल प्रश्नों में इसका उपयोग तेज और आसान है:
select T.ID
,MAX(X.cl) NameValues
from #YourTable T
CROSS APPLY
(select STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = T.ID)
FOR XML PATH(''))
,1,2,'') [cl]) X
GROUP BY T.ID
यदि समूह द्वारा ज्यादातर एक आइटम शामिल है, तो आप प्रदर्शन को निम्न तरीके से बेहतर कर सकते हैं:
SELECT
[ID],
CASE WHEN MAX( [Name]) = MIN( [Name]) THEN
MAX( [Name]) NameValues
ELSE
STUFF((
SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
FROM #YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
END
FROM #YourTable Results
GROUP BY ID
रिप्लेस फंक्शन और JSON PATH के लिए उपयोग करना
SELECT T3.DEPT, REPLACE(REPLACE(T3.ENAME,'{"ENAME":"',''),'"}','') AS ENAME_LIST
FROM (
SELECT DEPT, (SELECT ENAME AS [ENAME]
FROM EMPLOYEE T2
WHERE T2.DEPT=T1.DEPT
FOR JSON PATH,WITHOUT_ARRAY_WRAPPER) ENAME
FROM EMPLOYEE T1
GROUP BY DEPT) T3
नमूना डेटा और अधिक तरीकों के लिए यहां क्लिक करें
यदि आपके पास clr enable है तो आप GitHub से Group_Concat लाइब्रेरी का उपयोग कर सकते हैं
GROUP_CONCAT()
एग्रीगेट फ़ंक्शन के साथ आसानी से हल हो जाती है , लेकिन Microsoft SQL सर्वर पर इसे हल करना अधिक अजीब है। सहायता के लिए निम्नलिखित SO प्रश्न देखें: " संबंध के आधार पर एक रिकॉर्ड के खिलाफ कई रिकॉर्ड कैसे प्राप्त करें? "