将Raws转换为Columns中的字符串-仅在随后的两个是唯一的情况下

时间:2019-01-28 13:38:17

标签: sql sql-server tsql

enter image description here

如何修改下面的代码,使最终的群集字符串仅具有不重复前一个字符串的ErrorCodes,因此对于第3行,仅返回一个C(跳过第二个C),对于第1行,则返回A,C,A,B(由于相邻重复而跳过第二个A)。

    DECLARE @table1 TABLE
(
    [Case] INT,
    ErrorCode CHAR(1),
    [Date] varchar(20)
);

INSERT INTO @table1
VALUES
(1, 'A', '2018-01-25'),
(1, 'A', '2018-01-15'),
(1, 'C', '2018-01-15'),
(1, 'A', '2018-01-15'),
(1, 'A', '2018-01-15'),
(1, 'B', '2018-01-15'),
(2, 'D', '2018-01-26'),
(2, 'A', '2018-01-26'),
(2, 'D', '2018-01-25'),
(2, 'C', '2018-01-24'),
(2, 'C', '2018-01-24');

SELECT *
FROM @table1;

SELECT tabel2.[Case],
       tabel2.[Date],
       STUFF(
       (
           SELECT ', ' + ErrorCode
           FROM @table1 t1
           WHERE t1.[Case] = tabel2.[Case]
                 AND t1.[Date] = tabel2.[Date]
           FOR XML PATH('')
       ),
       1,
       1,
       ''
            ) AS [ErrorCode]
FROM
(SELECT DISTINCT [Case], [Date] FROM @table1) AS tabel2
ORDER BY tabel2.[Case],
         tabel2.[Date];

3 个答案:

答案 0 :(得分:1)

这就是我的方法。

首先,最好在表中有一个主键或唯一约束,该标识符可以唯一地标识每一行,即设置理论-101 :)。如果您不这样做,我以为是,这就是我添加PK或行号的方法:

;WITH Mytable AS 
(
   SELECT [case], [date], ErrorCode, ROW_NUMBER() OVER(ORDER BY (select NULL)) as rn
   FROM table1 
)

SELECT * FROM Mytable

现在,我们知道每行的顺序非常重要,这是您的任务所必需的,请使用子查询查找每行的下一个值:

,nextTable AS
(
    SELECT *, (SELECT errorcode 
                FROM Mytable mt2
                WHERE mt2.rn = mt1.rn+1 
                AND mt1.[Case] = mt2.[case] 
                AND mt1.[date] = mt2.[date]) as NextErrorCode
    FROM Mytable mt1
)

最后,使用CASE子句将它们相互比较,如果重复,则将其消除:

,final AS
(
SELECT[case], [date],
    CASE WHEN  ErrorCode = ISNULL(NextErrorCode, '') THEN NULL ELSE ErrorCode END as NewErrorCode
FROM nextTable
WHERE CASE WHEN  ErrorCode = ISNULL(NextErrorCode, '') THEN NULL ELSE ErrorCode END IS NOT NULL 
)

最简单的部分是,按您希望的方式将行连接成字符串:

SELECT @str =  COALESCE(@str + ',','') + NewErrorCode
FROM final
WHERE [case] = @case AND [date] = @date 

最终代码如下:

CREATE FUNCTION dbo.fn_groupConcat
(
@case int,
@date date
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @str varchar(200) 

;WITH Mytable AS 
(
    SELECT [case], [date], ErrorCode, ROW_NUMBER() OVER(ORDER BY (select NULL)) as rn
    FROM table1 
)
,nextTable AS
(
    SELECT *, (SELECT errorcode 
                FROM Mytable mt2
                WHERE mt2.rn = mt1.rn+1 AND mt1.[Case] = mt2.[case] AND mt1.[date] = mt2.[date]) as NextErrorCode
    FROM Mytable mt1
)
,final AS
(
    SELECT[case], [date],
    CASE WHEN  ErrorCode = ISNULL(NextErrorCode, '') THEN NULL ELSE ErrorCode END as NewErrorCode
    FROM nextTable
    WHERE CASE WHEN  ErrorCode = ISNULL(NextErrorCode, '') THEN NULL ELSE ErrorCode END IS NOT NULL 
)

SELECT @str =  COALESCE(@str + ',','') + NewErrorCode
FROM final
WHERE [case] = @case AND [date] = @date

RETURN(@str)
END

将该函数应用于您的表:

SELECT [case], [date], dbo.fn_groupConcat([case],[date]) as ErrorCode
FROM table1
GROUP BY [case], [date]

 ---------------------------------
|case |   date      |  ErrorCode  |
 ---------------------------------|
| 1   |  2018-01-15 |   A,C,A,B   |
| 1   |  2018-01-25 |   A         |
| 2   |  2018-01-24 |   C         |
| 2   |  2018-01-25 |   D         |
| 2   |  2018-01-26 |   D,A       |

答案 1 :(得分:0)

您刚刚错过了INNER DISTINCT

SELECT DISTINCT ', ' + ErrorCode
           FROM @table1 t1
           WHERE t1.[Case] = tabel2.[Case]
                 AND t1.[Date] = tabel2.[Date]
           FOR XML PATH('')

答案 2 :(得分:0)

您可以尝试以下查询。

SELECT  [Case],
        [Date]
       ,STUFF((SELECT ', ' + CAST(ErrorCode AS VARCHAR(10)) [text()]
         FROM @table1 
         WHERE [Case] = t.[Case] and [Date] = t.[Date]
         FOR XML PATH(''), TYPE)
        .value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM @Table1 t
GROUP BY [Case], [Date]

您可以找到实时演示here

要仅获取唯一值,您需要使用Distinct关键字,如下所示。

SELECT  [Case],
        [Date]
       ,STUFF((SELECT Distinct ', ' + CAST(ErrorCode AS VARCHAR(10)) [text()]
         FROM @table1 
         WHERE [Case] = t.[Case] and [Date] = t.[Date]
         FOR XML PATH(''), TYPE)
        .value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM @Table1 t
GROUP BY [Case], [Date]