2011-09-16 60 views
0

我试图创建一个查询到以下信息结合:TSQL合并多行到一行

FileID ErrorCode ErrorDesc    ErrorCount 
    1   4  Bad File Name    3 
    2   6  Bad File Code   56 
    3   4  Bad File Name    2 
    3  12  Line Length Invalid  3 
    3  17  Missing Req Fields  150 

我想基础上,FileID所有行结合起来,使所有的信息对于一个给定FileID会出现在同一行,如下:

1 4 Bad File Name  3 
2 6 Bad File Code 56 
3 4 Bad File Name  2  12 Line Length Invalid 3  17 Missing Req Fields 150 

我它运行到那里的问题将给予每个文件错误的未知量。它可能有1-50个错误,我想将所有这些信息合并到一行中。我不确定这是否可能,或者是否有另一种方法来查看此问题。我的最终目标是最终创建一份关于这些数据的报告。谢谢!

+1

有行对于任何给定的写到FileID一个最大数量? ErrorCodes的列表是已知的并且是有限的吗?如果有两个错误12,你需要分别报告他们两个吗?无论如何,我建议这个崩溃会在表现层处理得更好。 –

+0

根据错误总数将会有最大行数。在这种情况下,有50个错误,每个FileID最多有50个条目。所有错误代码在每个给定文件中都是唯一的。所以一个FileID只会列出每个错误代码一次。 – buzzzzjay

+1

如果您发布代码,XML或数据样本,**请**在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的“代码样本”按钮(“{}”)以精确地格式化和语法突出显示它! (并且没有杂乱的' '和'
'需要,要么!!) –

回答

3

比的Mikael是一个涉及多一点 - 的主要区别是,列在这里保持(但是列比第一个“排队”等每个错误代码)。

设置:

CREATE TABLE dbo.t 
(
    FileID INT, 
    ErrorCode INT, 
    ErrorDesc VARCHAR(255), 
    ErrorCount INT 
); 

INSERT dbo.t VALUES 
(1,4,'Bad File Name',3), 
(2,6,'Bad File Code',56), 
(3,4,'Bad File Name',2), 
(3,12,'Line Length Invalid',3), 
(3,17,'Missing Req Fields',150); 

代码:

DECLARE 
    @sql0 NVARCHAR(MAX) = N'', 
    @sql1 NVARCHAR(MAX) = N'', 
    @sql2 NVARCHAR(MAX) = N'', 
    @minC INT; 

SELECT @minC = MIN(ErrorCode) FROM dbo.t; 

SELECT @sql1 += REPLACE(',x$.ErrorCode AS Code$, 
    x$.ErrorDesc AS Desc$,x$.ErrorCount AS Count$', 
    '$', CONVERT(VARCHAR(12), ErrorCode)) 
    FROM dbo.t WHERE ErrorCode > @minC GROUP BY ErrorCode ORDER BY ErrorCode; 

SELECT @sql2 += REPLACE(' 
    LEFT OUTER JOIN x AS x$ ON z.FileID = x$.FileID 
    AND x$.ErrorCode = $ 
    AND x$.ErrorCode > z.ErrorCode', '$', CONVERT(VARCHAR(12), ErrorCode)) 
    FROM dbo.t WHERE ErrorCode > @minC GROUP BY ErrorCode ORDER BY ErrorCode; 

SET @sql0 = ';WITH y AS (
    SELECT FileID, ErrorCode, ErrorDesc, ErrorCount, 
     rn = ROW_NUMBER() OVER (PARTITION BY FileID ORDER BY ErrorCode) 
    FROM dbo.t 
), 
z AS (SELECT FileID, ErrorCode, ErrorDesc, ErrorCount FROM y WHERE rn = 1), 
x AS (SELECT FileID, ErrorCode, ErrorDesc, ErrorCount FROM y WHERE rn > 1) 
SELECT z.*' + @sql1 + ' FROM z 
' + @sql2; 

-- PRINT @sql0; -- to see what has been crafted  
EXEC sp_executesql @sql0; 
GO 

清理:

DROP TABLE dbo.t; 
GO 
+1

当然+1。我正在看它,以及...这可能是因为我正在为我的孩子做饭,但我不明白。必须坐下来了解一下你在这里做了什么:) –

+1

只是一个锚点和一堆左连接。我对此并不满意,因为对于任何FileID而言,任何ErrorCode都会出现空列,但不会出现在其他任何级别中。我仍然认为表现层是应该被处理的地方...... –

+0

令人印象深刻。这正是我想弄清楚的,它很复杂,但非常有趣。谢谢! – buzzzzjay

5
declare @T table (FileID int, ErrorCode int, ErrorDesc varchar(max), ErrorCount int) 

insert into @T values 
(1,    4,     'Bad File Name',   3), 
(2,    6,     'Bad File Code',   56), 
(3,    4,     'Bad File Name',   2), 
(3,    12,     'Line Length Invalid', 3), 
(3,    17,     'Missing Req Fields',  150) 

select FileID, 
     (select cast(ErrorCode as varchar(10))+' '+ErrorDesc+' '+cast(ErrorCount as varchar(10))+' ' 
     from @T as T2 
     where T1.FileID = T2.FileID 
     for xml path(''), type).value('.', 'varchar(max)') 
from @T as T1 
group by FileID 
+0

我想这样做,而不将它们合并成一列。思考? – buzzzzjay

+0

@buzzzzjay - 请回答亚伦给出的答案。动态是我知道的具有“未知/可变”列数的唯一方法。 –

+0

@buzzzzjay您真的正在为您自己解决您的问题。 –