Sql 在列中绘制为字符串-仅当两个后续字符串是唯一的时
如何修改下面的代码,使最终的集群字符串只包含错误代码,而错误代码与前一个字符串不重复,因此对于第3行,只返回一个C(跳过第二个C),对于第1行,则返回A、C、A、B(由于相邻的重复,跳过第二个A)Sql 在列中绘制为字符串-仅当两个后续字符串是唯一的时,sql,sql-server,tsql,Sql,Sql Server,Tsql,如何修改下面的代码,使最终的集群字符串只包含错误代码,而错误代码与前一个字符串不重复,因此对于第3行,只返回一个C(跳过第二个C),对于第1行,则返回A、C、A、B(由于相邻的重复,跳过第二个A) 您刚刚错过了内部不同的: SELECT DISTINCT ', ' + ErrorCode FROM @table1 t1 WHERE t1.[Case] = tabel2.[Case] AND t1.[Date] = ta
您刚刚错过了
内部
不同的
:
SELECT DISTINCT ', ' + ErrorCode
FROM @table1 t1
WHERE t1.[Case] = tabel2.[Case]
AND t1.[Date] = tabel2.[Date]
FOR XML PATH('')
您可以尝试以下查询
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]
你可以找到现场演示
要仅获取唯一值,需要使用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]
我就是这样做的
首先,您最好在表中有一个唯一标识每一行的主键或唯一约束,即集合论-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 |
正如我在你的文章中告诉你的,没有邻居数据这样的东西。例如,
2018-01-15
上案例1的所有值(在提供的示例中为ACAAB)没有隐式排序顺序。。。使用ACAAB时,同一查询可能会返回100次,但突然您会得到AAABC
,或BAACA
,或任何其他组合。。。简而言之:对于给定的数据,这是不可能的。如果插入了排序列(如附加的IDENTITY
值),则可以阅读LAG()
和LEAD()
。请不要使用varchar
存储日期。使用日期
或日期时间2(0)
或其他日期类型。。varchar(20)
比任何日期类型占用更多空间,并且不能保证内容有效。没有任何东西可以阻止某人插入2018-24-01
此外,相邻的以什么顺序插入?除非指定顺序,否则结果将以随机顺序返回,无论对服务器来说是什么样的顺序。除非明确指定订单,否则第一行很容易包含ACABA
、ABACA
或AAABC
。并行查询处理将以随机顺序返回结果。如何判断第二行是早于第四行还是晚于第四行(两者的日期相同).我所说的顺序:顺序是由正在处理的行的方向定义的:从上面的行到下面的行,所以例如2018-01-15:A C A B和我想保持相同的顺序,但只是消除第二个A:A C A B。OP发布了A,我提供了完全相同的解决方案。但在这种情况下,OP不希望得到一个不同的列表,而只是减少邻接兄弟。在投入更多时间之前,您可能需要阅读我的评论;-)这似乎不符合OP的要求。您的第一个查询将生成OP正在获取的相同内容,而您的第二个查询将删除所有重复,而不仅仅是重复相邻的重复。
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 |