SQL结果以逗号分隔

时间:2011-09-07 06:55:57

标签: sql stored-procedures sql-server-2008-r2

我有点陷入写存储过程的困境。情况就是这样。我有一张桌子,下面是插图

|   Name   |   Score   |

| A        | 10        |
| A        | 20        |
| A        | 30        |
| B        | 20        |
| B        | 50        |

我正试图从存储过程

获得如下结果
|   Name   |   Scores  |

| A        | 10,20,30  |
| B        | 20,50     |

是否可以从SQL查询或存储过程中获得此类结果?怎么样?

4 个答案:

答案 0 :(得分:0)

您可以创建CLR user-defined aggregate

using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.IO;
using System.Text;

[Serializable()]
[SqlUserDefinedAggregate(
    Format.UserDefined,
    IsInvariantToNulls=true,
    IsInvariantToDuplicates=false,
    IsInvariantToOrder=false,
    MaxByteSize=8000)]
public class Concat : IBinarySerialize
{
    #region Private fields
    private string separator;
    private StringBuilder intermediateResult;
    #endregion

    #region IBinarySerialize members
    public void Read(BinaryReader r)
    {
        this.intermediateResult = new StringBuilder(r.ReadString());
    }

    public void Write(BinaryWriter w)
    {
        w.Write(this.intermediateResult.ToString());
    }
    #endregion

    #region Aggregation contract methods
    public void Init()
    {
        this.separator = ", ";
        this.intermediateResult = new StringBuilder();
    }

    public void Accumulate(SqlString pValue)
    {
        if (pValue.IsNull)
        {
            return;
        }

        if (this.intermediateResult.Length > 0)
        {
            this.intermediateResult.Append(this.separator);
        }
        this.intermediateResult.Append(pValue.Value);
    }

    public void Merge(Concat pOtherAggregate)
    {
        this.intermediateResult.Append(pOtherAggregate.intermediateResult);
    }

    public SqlString Terminate()
    {
        return this.intermediateResult.ToString();
    }
    #endregion
}

并在查询中使用它,就像任何其他聚合函数一样:

SELECT Name, dbo.Concat(Score) AS Scores
FROM dbo.Table
GROUP BY Name

我博客上发布的文章A SQL CLR user-defined aggregate - notes on creating and debugging包含对此代码的详细说明。

答案 1 :(得分:0)

在这种情况下,COALESCE是你的朋友。我不是COALESCE的专家,我只知道它有用,所以如果你想深入挖掘,你可能想查一查。

下面的代码段会一次给你一行,给定在@Name中查找的名称,我将其转换为SQL Server中的一个函数,然后在上层SP中调用该函数,单词但请注意:如果结果集中包含NULL值,则会导致结果不正确。

    DECLARE @Name varchar
    SET @Name = 'A'

    DECLARE @Row varchar(max)

    SELECT
        @Row = COALESCE(@Row + ', ','') + CAST(Score AS varchar)

    FROM
        sotest2

    WHERE
        name = @Name

    SELECT @Name,@Row
顺便说一句,'sotest2'是表名,这就是我在db中所说的: - )

答案 2 :(得分:0)

在考虑评论后修改:

我建议您阅读Rob Farley's优秀博文Handling special characters with FOR XML PATH('')。他的解决方案允许在没有concern for fields that might have special characters的情况下对您的分组ID进行字符串连接。

DECLARE @t TABLE (Name CHAR(1), Score INT) 
INSERT @t VALUES 
('A', 10),
('A', 20), 
('A', 30), 
('B', 20), 
('B', 50)   

SELECT
  STUFF(
    (SELECT ', ' + CONVERT(VARCHAR(10), Score)
     FROM @t 
     WHERE Name = t.Name
     ORDER BY Score
     FOR XML PATH(''),
     TYPE).value('(./text())[1]','varchar(max)'),
   1, 2, '') AS Score     
FROM @t t 
GROUP BY Name 

答案 3 :(得分:0)

古怪的更新方法:

DECLARE @DistinctName TABLE
(
    Name VARCHAR(10) PRIMARY KEY
);
INSERT  @DistinctName (Name)
VALUES  ('A'),('B');
DECLARE @Test TABLE
(
    TestId INT IDENTITY(1,1) PRIMARY KEY
    ,Name VARCHAR(10) NOT NULL
    ,Score INT NOT NULL
    ,Result VARCHAR(1000) NOT NULL DEFAULT ''
);
INSERT  @Test (Name, Score)
VALUES  ('A',10),('A',20),('A',30),('B',40),('B',50);

DECLARE @OldName VARCHAR(10) = ''
        ,@IsNewGroup BIT = 1
        ,@Concat VARCHAR(1000);

WITH SourceCTE
AS
(
SELECT  TOP(1000) t.*
FROM    @Test t
ORDER BY t.Name
)
UPDATE  SourceCTE 
SET     @IsNewGroup = CASE WHEN @OldName <> Name THEN 1 ELSE 0 END
        ,@OldName = Name
        ,@Concat = Result = CASE WHEN @IsNewGroup = 1 THEN '' ELSE @Concat END + ',' + CAST(Score AS VARCHAR(10))
--OUTPUT    inserted.Name, inserted.TestId , inserted.Result

SELECT  dn.Name
        ,SUBSTRING(ca.Result,2,1000) Result
FROM    @DistinctName dn
CROSS APPLY
(
    SELECT  TOP(1) Result
    FROM    @Test t
    WHERE   t.Name = dn.Name 
    ORDER BY t.TestId DESC
) ca;

提及:

  1. 我在@Test表中添加了一个主键(TestId)。
  2. 请仔细阅读article about generating running totals using quirky update method以了解此方法。