2009-01-16 10 views
290

मैं माइक्रोसॉफ्ट एसक्यूएल सर्वर 2005 पर माइक्रोसॉफ्ट-आधारित ऐप माइग्रेट करने की कोशिश कर रहा हूं (पसंद से नहीं, लेकिन यह जीवन है)।माइक्रोसॉफ्ट एसक्यूएल सर्वर 2005 में group_concat MySQL फ़ंक्शन सिम्युलेट करना?

मूल एप्लिकेशन में, हम लगभग पूरी तरह एएनएसआई-एसक्यूएल अनुरूप बयान करता था, एक महत्वपूर्ण अपवाद के साथ - हम काफी अक्सर MySQL के group_concat समारोह का इस्तेमाल किया।

group_concat, वैसे, यह करता है: का, कहते हैं, कर्मचारी के नाम और परियोजनाओं एक मेज दिया ...

SELECT empName, projID FROM project_members; 

रिटर्न:

ANDY | A100 
ANDY | B391 
ANDY | X010 
TOM | A100 
TOM | A510 

... और यहां आप क्या group_concat साथ मिलती है:

SELECT 
    empName, group_concat(projID SEPARATOR '/') 
FROM 
    project_members 
GROUP BY 
    empName; 

रिटर्न:

ANDY | A100/B391/X010 
TOM | A100/A510 

तो मैं क्या जानना चाहता हूं: क्या SQL सर्वर में उपयोगकर्ता द्वारा परिभाषित फ़ंक्शन लिखना संभव है, जो group_concat की कार्यक्षमता को अनुकरण करता है?

मैं UDFs का उपयोग कर लगभग कोई अनुभव, संग्रहित प्रक्रियाओं, या कुछ भी ऐसा, बस सीधे-अप एसक्यूएल है, इसलिए बहुत ज्यादा स्पष्टीकरण :)

+0

कुछ आसान लिंक: http://www.postgresonline.com/journal/archives/191-stringagg.html और http://consultingblogs.emc.com/jamiethomson/archive/2009/07/16/string -ग्रेगेशन-इन-टी-एसक्यूएल-amp-pl-sql.aspx – bernhof

+0

संभावित डुप्लिकेट [मैं एक क्वेरी क्वेरी का उपयोग कर अल्पविराम से अलग सूची कैसे बना सकता हूं?] (http://stackoverflow.com/questions/1817985/how -do-i-create-a-अल्पविराम से अलग-सूची-उपयोग-ए-एसक्यूएल-क्वेरी) - वह पोस्ट व्यापक है इसलिए मैं इसे एक कैनोनिकल – TMS

+0

के रूप में चुन सकता हूं [एसक्यूएल समूह \ _concat फ़ंक्शन SQL सर्वर में संभावित डुप्लिकेट] (http://stackoverflow.com/questions/8868604/sql-group-concat-function-in-sql-server) – Trikaldarshi

उत्तर

146

कोई वास्तविक आसान तरीका यह करने के लिए की ओर गलती करें। हालांकि, वहां बहुत सारे विचार हैं।

Best one I've found:

SELECT table_name, LEFT(column_names , LEN(column_names)-1) AS column_names 
FROM information_schema.columns AS extern 
CROSS APPLY 
(
    SELECT column_name + ',' 
    FROM information_schema.columns AS intern 
    WHERE extern.table_name = intern.table_name 
    FOR XML PATH('') 
) pre_trimmed (column_names) 
GROUP BY table_name, column_names; 

या एक संस्करण है कि ठीक से काम करता डेटा नीचे कोड आप अपने प्रोजेक्ट गुणों पर PermissionLevel = बाहरी सेट करने के लिए के साथ वर्ण हो सकता है अगर इस तरह के रूप <

WITH extern 
    AS (SELECT DISTINCT table_name 
     FROM INFORMATION_SCHEMA.COLUMNS) 
SELECT table_name, 
     LEFT(y.column_names, LEN(y.column_names) - 1) AS column_names 
FROM extern 
     CROSS APPLY (SELECT column_name + ',' 
        FROM INFORMATION_SCHEMA.COLUMNS AS intern 
        WHERE extern.table_name = intern.table_name 
        FOR XML PATH(''), TYPE) x (column_names) 
     CROSS APPLY (SELECT x.column_names.value('.', 'NVARCHAR(MAX)')) y(column_names) 
+0

यह उदाहरण मेरे लिए काम करता है, लेकिन मैंने एक और एकत्रीकरण करने की कोशिश की और यह काम नहीं किया, मुझे दिया एक त्रुटि: "सहसंबंध नाम 'pre_trimmed' को खंड से कई बार निर्दिष्ट किया गया है।" – PhilChuang

+6

'pre_trimmed' subquery के लिए सिर्फ एक उपनाम है। उप-सामानों के लिए उपनामों की आवश्यकता होती है और उन्हें अद्वितीय होना चाहिए, इसलिए किसी अन्य सबक्वायरी के लिए इसे कुछ अद्वितीय में बदलना है ... – Koen

+0

क्या आप table_name के बिना कॉलम नाम के एक उदाहरण दिखा सकते हैं, यह भ्रमित है। –

6

आपके द्वारा तैनात करने से पहले, और बाहरी कोड पर भरोसा करने के लिए डेटाबेस को बदलें ("वैकल्पिक डेटाबेस_नाम सेट ट्रस्टवॉर्नी चालू" चलाकर सुरक्षा जोखिमों और विकल्पों [जैसे प्रमाणपत्रों] के बारे में कहीं और पढ़ना सुनिश्चित करें।

using System; 
using System.Collections.Generic; 
using System.Data.SqlTypes; 
using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
using Microsoft.SqlServer.Server; 

[Serializable] 
[SqlUserDefinedAggregate(Format.UserDefined, 
MaxByteSize=8000, 
IsInvariantToDuplicates=true, 
IsInvariantToNulls=true, 
IsInvariantToOrder=true, 
IsNullIfEmpty=true)] 
    public struct CommaDelimit : IBinarySerialize 
{ 


[Serializable] 
private class StringList : List<string> 
{ } 

private StringList List; 

public void Init() 
{ 
    this.List = new StringList(); 
} 

public void Accumulate(SqlString value) 
{ 
    if (!value.IsNull) 
    this.Add(value.Value); 
} 

private void Add(string value) 
{ 
    if (!this.List.Contains(value)) 
    this.List.Add(value); 
} 

public void Merge(CommaDelimit group) 
{ 
    foreach (string s in group.List) 
    { 
    this.Add(s); 
    } 
} 

void IBinarySerialize.Read(BinaryReader reader) 
{ 
    IFormatter formatter = new BinaryFormatter(); 
    this.List = (StringList)formatter.Deserialize(reader.BaseStream); 
} 

public SqlString Terminate() 
{ 
    if (this.List.Count == 0) 
    return SqlString.Null; 

    const string Separator = ", "; 

    this.List.Sort(); 

    return new SqlString(String.Join(Separator, this.List.ToArray())); 
} 

void IBinarySerialize.Write(BinaryWriter writer) 
{ 
    IFormatter formatter = new BinaryFormatter(); 
    formatter.Serialize(writer.BaseStream, this.List); 
} 
    } 

मैं इस परीक्षण किया है एक प्रश्न है कि लग रहा है का उपयोग कर की तरह:

SELECT 
dbo.CommaDelimit(X.value) [delimited] 
FROM 
(
    SELECT 'D' [value] 
    UNION ALL SELECT 'B' [value] 
    UNION ALL SELECT 'B' [value] -- intentional duplicate 
    UNION ALL SELECT 'A' [value] 
    UNION ALL SELECT 'C' [value] 
) X 

और पैदावार: ए, बी, सी, डी

43

संभवतः भी, देर से अब लाभदायक लेकिन क्या यह चीजों को करने का सबसे आसान तरीका नहीं है?

SELECT  empName, projIDs = replace 
          ((SELECT Surname AS [data()] 
           FROM project_members 
           WHERE empName = a.empName 
           ORDER BY empName FOR xml path('')), ' ', REQUIRED SEPERATOR) 
FROM   project_members a 
WHERE  empName IS NOT NULL 
GROUP BY empName 
+0

दिलचस्प। मैंने पहले ही परियोजना को समाप्त कर लिया है, लेकिन मैं इस विधि को आज़मा दूंगा। धन्यवाद! – DanM

+6

अच्छी चाल - केवल समस्याएं उपनामों के साथ उपनामों के लिए है, यह स्थान को विभाजक के साथ बदल देगा। –

+0

मुझे खुद को ऐसी समस्या का सामना करना पड़ा है, मार्क। दुर्भाग्यवश, जब तक एमएसएसक्यूएल समय के साथ नहीं मिलता है और GROUP_CONCAT पेश करता है, यह सबसे ऊपर की ओर से गहन विधियों में से एक है जो मैं यहां आवश्यक चीज़ों के साथ आने में सक्षम हूं। –

4

बारे में जम्मू Hardiman का जवाब, कैसे के बारे में:

SELECT empName, projIDs= 
    REPLACE(
    REPLACE(
     (SELECT REPLACE(projID, ' ', '-somebody-puts-microsoft-out-of-his-misery-please-') AS [data()] FROM project_members WHERE empName=a.empName FOR XML PATH('')), 
     ' ', 
     '/'), 
    '-somebody-puts-microsoft-out-of-his-misery-please-', 
    ' ') 
    FROM project_members a WHERE empName IS NOT NULL GROUP BY empName 

वैसे, "उपनाम" लिखने में कोई त्रुटि का प्रयोग होता है या मैं यहाँ एक अवधारणा को समझने नहीं कर रहा हूँ?

वैसे भी, बहुत बहुत शुक्रिया लोग cuz यह मुझे काफी कुछ समय :)

+1

इसके बजाय अगर आप मुझसे पूछें और उत्तर के रूप में सभी सहायक नहीं हैं तो असभ्य जवाब दें। –

+1

केवल यह देखकर ... मेरा मतलब यह नहीं था कि जब मैं एसक्यूएल सर्वर (अभी भी हूं) से बहुत निराश था। वास्तव में इस पोस्ट के जवाब वास्तव में सहायक थे; संपादित करें: यह सहायक बीटीडब्ल्यू क्यों नहीं था? यह मेरे लिए चाल है – user422190

6

इन की कोशिश की लेकिन बचाया एमएस SQL ​​सर्वर 2005 में अपने उद्देश्यों के लिए निम्नलिखित सबसे अधिक उपयोगी है, जो मैं xaprb

declare @result varchar(8000); 

set @result = ''; 

select @result = @result + name + ' ' 

from master.dbo.systypes; 

select rtrim(@result); 
में पाया था

@ मार्क जैसा आपने बताया है वह अंतरिक्ष चरित्र था जिसने मेरे लिए मुद्दों का कारण बना दिया।

146

मुझे पार्टी के लिए थोड़ा देर हो सकती है लेकिन यह विधि मेरे लिए काम करती है और COALESCE विधि से आसान है।

SELECT STUFF(
      (SELECT ',' + Column_Name 
       FROM Table_Name 
       FOR XML PATH ('')) 
      , 1, 1, '') 
+0

यह केवल दिखाता है कि मूल्यों को कैसे समेकित करना है - group_concat उन्हें समूह द्वारा जोड़ता है, जो अधिक चुनौतीपूर्ण है (और ओपी को क्या चाहिए)। ऐसा करने के लिए SO 15154644 के स्वीकृत उत्तर को देखें - WHERE क्लॉज महत्वपूर्ण जोड़ – DJDave

6

परियोजनाओं कई परियोजना प्रबंधकों है कि से सभी परियोजना प्रबंधक के नाम जोड़ करने के लिए लिखें:

SELECT a.project_id,a.project_name,Stuff((SELECT N'/ ' + first_name + ', '+last_name FROM projects_v 
where a.project_id=project_id 
FOR 
XML PATH(''),TYPE).value('text()[1]','nvarchar(max)'),1,2,N'' 
) mgr_names 
from projects_v a 
group by a.project_id,a.project_name 
27

Codeplex पर GROUP_CONCAT परियोजना पर एक नज़र डालें, मुझे लगता है कि मैं तुम्हारे लिए वास्तव में क्या खोज रहे हैं करता है :

This project contains a set of SQLCLR User-defined Aggregate functions (SQLCLR UDAs) that collectively offer similar functionality to the MySQL GROUP_CONCAT function. There are multiple functions to ensure the best performance based on the functionality required...

+5

डाउनवोट क्यों है? कृपया समझाएं ... – MaxiWheat

+5

मैंने इसका उपयोग किया है और यह अब तक अच्छा काम करता है। –

+1

@MaxiWheat: वोट पर क्लिक करने से पहले बहुत से लोग प्रश्न या उत्तर सावधानी से नहीं पढ़ते हैं। यह सीधे उनकी गलती के कारण मालिक पद पर प्रभाव डालता है। –

25

एसक्यूएल सर्वर 2017 एक नई एकीकृत फ़ंक्शन परिचय करता

01,235,

STRING_AGG (expression, separator)

Concatenates the values of string expressions and places separator values between them. The separator is not added at the end of string.

श्रेणीबद्ध तत्वों WITHIN GROUP (ORDER BY some_expression)

जोड़कर संस्करणों 2005-2016 मैं आम तौर पर स्वीकार किए जाते हैं जवाब में XML विधि का उपयोग करने के लिए द्वारा आदेश दिया जा सकता है।

हालांकि कुछ परिस्थितियों में यह असफल हो सकता है। जैसे डेटा concatenated जा करने के लिए है या नहीं CHAR(29) आप देख

FOR XML could not serialize the data ... because it contains a character (0x001D) which is not allowed in XML.

एक और अधिक मजबूत विधि है कि सभी पात्रों के साथ सौदा कर सकते हैं एक CLR कुल उपयोग करने के लिए किया जाएगा। हालांकि इस दृष्टिकोण के साथ संयोजित तत्वों को ऑर्डर करना अधिक कठिन है।

एक चर को आवंटित करने की विधि not guaranteed है और उत्पादन कोड से बचा जाना चाहिए।

+0

यह अब Azure SQL में भी उपलब्ध है: https://azure.microsoft.com/en-us/roadmap/new-t-sql-string-functions-in-azure-sql-database/ –

संबंधित मुद्दे