【问题标题】:How to make row data comma separated in SQL?如何在 SQL 中使行数据逗号分隔?
【发布时间】:2010-12-07 18:33:12
【问题描述】:

我有一个查询返回以下输出。

(结果的数量并不总是相同,意味着有时它会给出 3 个类别,有时会给出 8 个类别等。)

CategoryName

  Test1
  Test2
  Test3

现在我希望存储过程以逗号分隔格式返回这些日期。 例如输出字符串应该是这样的:Test1,Test2,Test3

您能告诉我如何实现这一目标吗?

【问题讨论】:

标签: sql-server function stored-procedures


【解决方案1】:

这适用于您数据中的所有字符:

set nocount on;
declare @YourTable table (BirthDay datetime, PersonName varchar(20))
insert into @YourTable VALUES ('1-10-2010',     'Joe'  )
insert into @YourTable VALUES ('2-10-2010',     'Bob  <&>'  )
insert into @YourTable VALUES ('2-10-2010',     'Alice')
set nocount off


--Concatenation with FOR XML and eleminating control/encoded character expansion "& < >"
SELECT
    p1.BirthDay
        ,STUFF(
                   (SELECT
                        ', ' + p2.PersonName
                        FROM @YourTable p2
                        WHERE p2.BirthDay=p1.BirthDay
                        ORDER BY p2.PersonName
                        FOR XML PATH(''), TYPE
                   ).value('.','varchar(max)')
                   ,1,2, ''
              ) AS PersonNames
    FROM @YourTable p1
    GROUP BY p1.BirthDay

输出:

BirthDay                PersonNames
----------------------- ------------------------
2010-01-10 00:00:00.000 Joe
2010-02-10 00:00:00.000 Alice, Bob  <&>

(2 row(s) affected)

【讨论】:

    【解决方案2】:

    试试COALESCEISNULL

    DECLARE @returnValue varchar(MAX)
    
    SELECT
      @returnValue = COALESCE(@returnValue + ', ', '') + CategoryName
    FROM
      TableName
    

    【讨论】:

    • OP 没有说明 CategoryName 是否可以为空。但是,在查询中,您可能希望在 CategoryName 周围添加 COALESCE 或 ISNULL 以防止 NULL 消除整个字符串。进入(连接字符串时避免为NULL)是一个好习惯,这将防止以后棘手的盲目调试。
    【解决方案3】:

    看看类似(完整的工作示例

    DECLARE @Table TABLE(
            ID INT,
            Val VARCHAR(50)
    )
    INSERT INTO @Table (ID,Val) SELECT 1, 'A'
    INSERT INTO @Table (ID,Val) SELECT 1, 'B'
    INSERT INTO @Table (ID,Val) SELECT 1, 'C'
    INSERT INTO @Table (ID,Val) SELECT 2, 'B'
    INSERT INTO @Table (ID,Val) SELECT 2, 'C'
    
    --Concat
    SELECT  t.ID,
            STUFF((
                    SELECT  ',' + t1.Val 
                    FROM    @Table AS t1 
                    WHERE   t1.ID = t.ID 
                    FOR XML PATH('')
                    ), 1, 1, '')
    FROM    @Table t
    GROUP BY t.ID
    

    此外,您可能会发现谷歌搜索会提供很多答案。

    【讨论】:

    • 如果您的数据包含以下常见字符,则此方法将不起作用:&lt;&gt;&amp; 等。
    【解决方案4】:

    一个意思:

    SELECT STUFF((
      SELECT ',' + CategoryName AS [text()]
      FROM YourTable
      FOR XML PATH('')
    ), 1, 1, '')
    

    ...但要注意将被转义的 XML 实体 - 例如&amp; =&gt; &amp;amp;

    【讨论】:

    • 您可以轻松避免特殊 XML 字符的问题,请参阅我的答案。
    【解决方案5】:

    只需在存储过程中修改 KM 答案

    ALTER Procedure [dbo].[Payroll_rptAbsentReport]
    @FromDate DateTime,
    @ToDate DateTime,
    @GFacatoryID UniqueIdentifier
    As
    Begin
    -- Temporary table for Row data seperation
    CREATE TABLE TestTable(GEmployeeGenInfoID uniqueidentifier, dtAttendDateTime varchar(max))
    INSERT INTO 
                TestTable(GEmployeeGenInfoID, dtAttendDateTime)
          SELECT 
                 Payroll_tblAttendance.GEmployeeGenInfoID
                ,CONVERT(VARCHAR(max), dtAttendDateTime, 105)dtAttendDateTime
          FROM  Payroll_tblAttendance
                INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Payroll_tblAttendance.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
                WHERE Payroll_tblAttendance.DayStatusID = 0  AND EmployeeGenInfo.GFactoryID=@GFacatoryID AND Payroll_tblAttendance.dtAttendDateTime Between @FromDate and @ToDate ORDER BY dtAttendDateTime
    -- Final expected output
    SELECT DISTINCT
          EmployeeGenInfo.StrEmpName
         ,EmployeeGenInfo.StrEmpID
         ,Attendence.CardNo
          ,EmployeeDesignation.StrDesignationName
          ,EmployeeDept.StrDepartmentName
          -- Count data will be in one column
          ,(Select COUNT(*) From TestTable Where GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID) TotalAbsent
          -- Row data set into one column seperate by coma
          ,substring( ( SELECT ', ' + dtAttendDateTime as [text()]
                           FROM TestTable 
                           WHERE  GEmployeeGenInfoID = Attendence.GEmployeeGenInfoID
                           FOR XML path(''), elements
                         ), 3, 1000
                        )  List
    FROM 
         Payroll_tblAttendance as Attendence
         INNER JOIN TestTable on TestTable.GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID
         INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Attendence.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
         INNER JOIN PIS.dbo.PIS_tblDesignationInfo as EmployeeDesignation ON EmployeeGenInfo.GDesignationInfoID= EmployeeDesignation.GDesignationInfoID
         INNER JOIN PIS.dbo.PIS_tblDepartment as EmployeeDept ON EmployeeGenInfo.GDepartmentID= EmployeeDept.GDepartmentID
         WHERE EmployeeGenInfo.GFactoryID=@GFacatoryID AND Attendence.DayStatusID = 0 AND Attendence.dtAttendDateTime Between @FromDate and @ToDate
    DROP TABLE TestTable
    END 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-05
      • 1970-01-01
      相关资源
      最近更新 更多