문제

MySQL 기반 앱을 Microsoft SQL Server 2005로 마이그레이션하려고합니다 (선택이 아니라 생명입니다).

원래 앱에서 우리는 사용했습니다 거의 하나의 중요한 예외를 가진 전적으로 ANSI-SQL 호환 진술서-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

그래서 내가 알고 싶은 것은 다음과 같은 것입니다. group_concat?

나는 UDF, 저장된 절차 또는 그와 비슷한 경험이 거의 없으므로 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) 

다른 팁

나는 파티에 조금 늦었을 수도 있지만이 방법은 나에게 효과적이며 Coalesce 방법보다 쉽습니다.

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의 경우 XML에서 허용되지 않는 문자 (0x001D)가 포함되어 있기 때문에 데이터를 직렬화 할 수 없습니다.

모든 문자를 다룰 수있는보다 강력한 방법은 CLR 집계를 사용하는 것입니다. 그러나이 접근법에서는 합의 된 요소에 주문을 적용하는 것이 더 어렵습니다.

변수에 할당하는 방법은 다음과 같습니다 보장되지 않습니다 생산 코드에서는 피해야합니다.

살펴보십시오 Group_Concat Github 프로젝트, 나는 당신이 검색하는 것을 정확하게 수행한다고 생각합니다.

이 프로젝트에는 MySQL Group_Concat 함수와 유사한 기능을 제공하는 SQLCLR 사용자 정의 집계 함수 (SQLCLR UDA) 세트가 포함되어 있습니다. 필요한 기능을 기반으로 최상의 성능을 보장하기위한 여러 기능이 있습니다 ...

여러 프로젝트 관리자가있는 프로젝트의 모든 프로젝트 관리자 이름을 연결하기 위해 다음을 작성합니다.

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

아래 코드를 사용하면 배포하기 전에 프로젝트 속성에 대한 Aprismentlevel = 외부를 설정하고 데이터베이스를 변경하여 데이터베이스를 변경하여 외부 코드를 신뢰하도록 데이터베이스를 변경하여 데이터베이스 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 Server 2005에서의 목적을 위해 다음은 가장 유용했으며 xaprb

declare @result varchar(8000);

set @result = '';

select @result = @result + name + ' '

from master.dbo.systypes;

select rtrim(@result);

@mark 당신이 언급했듯이 그것은 나에게 문제를 일으킨 공간 캐릭터였습니다.

J 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

그건 그렇고, "성"의 사용은 오타 또는 여기서 개념을 이해하지 못하는가?

어쨌든, 감사합니다.

저의 동료 Googlers를 위해, 여기에 더 복잡한 솔루션으로 어려움을 겪은 후 저를 위해 일한 매우 간단한 플러그 앤 플레이 솔루션이 있습니다.

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

이에 대한 모든 크레딧은 여기로 이동합니다.https://social.msdn.microsoft.com/forums/sqlserver/en-us/9508abc2-46e7-4186-b57f-7f368374e084/replicating-groupconcat-function-of-mysql-in-sql-server?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top