سؤال

أنا أحاول أن الهجرة يستند إلى الخلية التطبيق إلى Microsoft SQL Server 2005 (وليس عن طريق الاختيار, ولكن هذه هي الحياة).

في التطبيق الأصلي ، كنا تقريبا تماما ANSI SQL متوافقة مع البيانات مع واحدة كبيرة استثناء -- كنا الخلية 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 Server الذي يحاكي وظيفة group_concat?

لدي ما يقرب من أي تجربة استخدام UDFs الإجراءات المخزنة أو أي شيء من هذا القبيل, فقط متابعة مباشرة SQL, لذا يرجى يخطئ على جانب من الكثير من الشرح :)

هل كانت مفيدة؟

المحلول

ولا طريقة سهلة الحقيقية للقيام بذلك. الكثير من الأفكار هناك، وبالرغم من ذلك.

أفضل واحد لقد وجدت :

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;

وأو الإصدار الذي يعمل بشكل صحيح إذا كان قد تحتوي على بيانات الأحرف مثل <

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) 

نصائح أخرى

وقد أكون متأخرا بعض الشيء للحزب ولكن هذا الأسلوب يعمل بالنسبة لي وأسهل من الطريقة تلتحم.

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

وربما بعد فوات الأوان لتكون ذات فائدة الآن، ولكن أليس هذا هو أسهل طريقة لفعل الأشياء؟

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

SQL Server عام 2017 لا أعرض دالة تجميع جديدة

STRING_AGG ( expression, separator).

يسلسل قيم السلسلة تعابير الأماكن فاصل القيم بينهما.فاصل لا يضاف في نهاية السلسلة.

فإن متصلا عناصر يمكن طلبها عن طريق إلحاق WITHIN GROUP (ORDER BY some_expression)

للحصول على إصدارات 2005-2016 أنا عادة استخدام XML طريقة في الجواب المقبول.

هذا يمكن أن تفشل في بعض الظروف ذلك.على سبيل المثالإذا كانت البيانات إلى أن تكون متصلا يحتوي على CHAR(29) ترى

لـ XML لا يمكن إجراء تسلسل البيانات ...لأنه يحتوي على حرف (0x001D) الذي لا يسمح في XML.

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

طريقة تعيين إلى متغير هو ليست مضمونة وينبغي تجنبها في إنتاج التعليمات البرمجية.

وإلقاء نظرة على المشروع GROUP_CONCAT على جيثب، وأعتقد أنني يفعل بالضبط ما كنت تبحث عن:

<اقتباس فقرة>   

وهذا المشروع يحتوي على مجموعة من SQLCLR دالات التجميع المعرفة من قبل المستخدم (SQLCLR UDAs) التي تقدم بشكل جماعي وظائف مماثلة لوظيفة الخلية GROUP_CONCAT. هناك وظائف متعددة لضمان أفضل أداء على أساس الوظيفة المطلوبة ...

لسلسلة جميع الأسماء مدير المشروع من المشاريع التي لها مديري المشاريع متعددة إرسال:

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

ومع رمز أدناه لديك لتعيين PermissionLevel = الخارجي عن خصائص المشروع الخاص بك قبل نشر، وتغيير قاعدة البيانات إلى الثقة كود خارجي (تأكد من قراءة أماكن أخرى حول المخاطر الأمنية والبدائل [مثل شهادات]) عن طريق تشغيل "ALTER DATABASE database_name SET جديرا بالثقة في ".

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 

والعوائد: A، B، C، D

وحاولت هذه ولكن لأغراض بلدي في MS SQL خادم 2005 كان ما يلي مفيدا للغاية، التي وجدت على الموقع xaprb

declare @result varchar(8000);

set @result = '';

select @result = @result + name + ' '

from master.dbo.systypes;

select rtrim(@result);

وMark كما ذكرتم كان حرف مسافة التي تسببت في القضايا بالنسبة لي.

وعن إجابة J هارديمان، وكيف حول:

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

وبالمناسبة، هو استخدام "اللقب" خطأ مطبعي أو هل أنا لا تفهم مفهوم هنا؟

وعلى أي حال، وذلك بفضل الكثير الرجال كوز أنها وفرت لي بعض الوقت:)

لزملائي الغوغليين هناك، وهنا بسيط جدا حل التوصيل والتشغيل التي عملت بالنسبة لي بعد صراع مع حلول أكثر تعقيدا لفترة من الوقت:

SELECT
distinct empName,
NewColumnName=STUFF((SELECT ','+ CONVERT(VARCHAR(10), projID ) 
                     FROM returns 
                     WHERE empName=t.empName FOR XML PATH('')) , 1 , 1 , '' )
FROM 
returns t

لاحظ ان كان لي لتحويل ID إلى VARCHAR من أجل سلسلة كسلسلة. إذا لم يكن لديك للقيام بذلك، وهنا نسخة حتى أبسط:

SELECT
distinct empName,
NewColumnName=STUFF((SELECT ','+ projID
                     FROM returns 
                     WHERE empName=t.empName FOR XML PATH('')) , 1 , 1 , '' )
FROM 
returns t

وكل الفضل في هذا يعود إلى هنا: <وأ href = "https://social.msdn.microsoft.com/Forums/sqlserver/en-US/9508abc2-46e7-4186-b57f-7f368374e084/replicating-groupconcat-function-of-mysql-in-sql-server ؟ المنتدى = تي-سكيول "يختلط =" نوفولو noreferrer "> https://social.msdn.microsoft.com/Forums/sqlserver/en-US/9508abc2-46e7-4186-b57f-7f368374e084/replicating-groupconcat-function-of- الخلية في ومزود خادم؟ المنتدى = تي-سكيول

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top