2016-02-26 58 views
1

不幸的是,我一直坚持这个项目的方式。我需要做的是拿一张大约有100个字段的表格,比较两个记录,确定哪些字段不匹配。SQL Server数据透视/不透视整个表格(100+个字段)

我能想到的是转动他们的最好办法,所以这个:

KeyID Field1 Field2 Field3 Field4 Field5 Field6 
42  Apples Pears Blue  Hills Dog  iPhone 
65  Apples Plums Red  Hills Cat  iPhone 

变成这样:

FieldName KeyID_42 KeyID_65 
Field1  Apples  Apples 
Field2  Pears  Plums 
Field3  Blue  Red 
Field4  Hills  Hills 
Field5  Dog   Cat 
Field6  iPhone  iPhone 

,然后我可以运行对像的查询:

我应该留下这个:

FieldName KeyID_42 KeyID_65 
Field2  Pears  Plums 
Field3  Blue  Red 
Field5  Dog   Cat 

但是,对于包含100个左右字段的表格,在PIVOT语句中列出它们中的每一个都不会很漂亮。我可能不得不在稍后的另一张桌子上做这个。

有没有简单的方法来实现这一目标?一个不需要单独列出每个字段?

编辑:

我在这一点上,但越来越多的错误是这样的:Invalid column name 'UpdateTime'.

我正在使用的代码是这样的:

DECLARE @colsUnpivot AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @colsUnpivot 
    = stuff((select ','+quotename(C.name) 
      FROM sys.columns c 
      WHERE c.object_id = OBJECT_ID('dbo.tblSQLAdminInventory') 
      --AND C.Name <> 'EffectiveDate' 
      for xml path('')), 1, 1, '') 

set @query 
    = 'select KeyID, ID1, ID2 
    from tblSQLAdminInventory 
    unpivot 
    (
     KeyID 
     for ID1 in ('+ @colsunpivot +') 
    ) u 
    unpivot 
    (
     KeyID 
     for ID2 in ('+ @colsunpivot +') 
    ) u  
    ' 

exec sp_executesql @query; 
+0

没有列出所有领域,你需要使用'动态sql'去解决你的结果。 SO的几个例子就是这样做的。 – sgeddes

+0

Double unpivot不会诀窍。为什么不转光两次? –

+0

Where子句总是WHERE KeyID_42 <> KeyID_65,或者这也需要动态化吗? –

回答

0

逆透视只有一次,然后写如下:

;WITH cte AS (
    -- the query with unpivot but only once 
    -- UNPIVOT(value FOR ID IN (...)) 
) 
SELECT 
    * 
FROM 
    cte AS c1 
    INNER JOIN cte AS c2 ON 
     c2.ID=c1.ID 
WHERE 
    c1.KeyId=42 AND 
    c2.KeyId=65 AND 
    c1.value<>c2.value; 
0

这应该做的伎俩,因为它是动态的,你不需要担心的字段数:

假设:列名总是会在格式字段

的样本数据:

CREATE TABLE temp2 (KeyID INT, Field1 VARCHAR(20), Field2 VARCHAR(20), Field3 VARCHAR(20), Field4 VARCHAR(20), Field5 VARCHAR(20), Field6 VARCHAR(20)); 

INSERT INTO temp2 
VALUES 
     (42, 'Apples', 'Pears', 'Blue', 'Hills', 'Dog', 'iPhone'), 
     (65, 'Apples', 'Plums', 'Red', 'Hills', 'Cat', 'iPhone'); 

查询:

-- Where clause params 
DECLARE @whereClauseParam VARCHAR(MAX) = '[42] <> [65]' --<-- User will need to determine what the condition will be 

--Get the Fields required for the initial pivot 
DECLARE @Fields VARCHAR(MAX)= ''; 

SELECT @Fields+=QUOTENAME(t.name)+', ' 
FROM sys.columns AS t 
WHERE t.object_id = OBJECT_ID('temp2') 
     AND t.name LIKE 'Field[0-9]%'; 

-- Get the KeyId's with alias added 
DECLARE @keyIDs VARCHAR(MAX)= ''; 

SELECT @keyIDs+=QUOTENAME(t.KeyID)+' AS [KeyID_'+CAST(t.KeyID AS VARCHAR(10))+'], ' 
FROM temp2 AS t; 

-- Get the KeyId's without alias 
DECLARE @keyIDs1 VARCHAR(MAX)= ''; 

SELECT @keyIDs1+=QUOTENAME(t.KeyID)+', ' 
FROM temp2 AS t; 

--Generate Dynamic SQL 
DECLARE @SQL2 VARCHAR(MAX)= 'SELECT Value AS FieldName,'; 

SELECT @SQL2+=SUBSTRING(@keyIDs, 1, LEN(@keyIDs)-1)+' 
FROM 
(SELECT KeyID , Value , FieldName 
FROM 
    (SELECT KeyID,'+SUBSTRING(@Fields, 1, LEN(@Fields)-1)+' 
    FROM temp2) p --<-- you will need to change the name to point to your table 
UNPIVOT 
    (FieldName FOR value IN 
     ('+SUBSTRING(@Fields, 1, LEN(@Fields)-1)+') 
)AS unpvt) AS SourceTable 
PIVOT 
(
MAX(FieldName) 
FOR KeyID IN ('+SUBSTRING(@keyIDs1, 1, LEN(@keyIDs1)-1)+') 
) AS PivotTable 
WHERE '[email protected] 

PRINT(@SQL2); 
EXECUTE(@SQL2); 

结果:

enter image description here

在回应评论“这将返回错误:传递给左或子字符串函数无效长度参数:)”:

enter image description here

+0

Kamran joon,这将返回错误:无效的长度参数传递给左或SUBSTRING函数:) – FLICKER

+0

@ FLICKER你确定你已经正确地复制了代码。我只是跑了,它运行良好! –

+1

有一个值(小写v)。它应该是Value(大写字母V)。由于我的整理,我正在犯错误。现在,它的工作。谢谢 – FLICKER