输出交叉引用Matrix导致SQL查询

时间:2014-06-04 09:04:07

标签: sql sql-server sql-server-2008

假设我有一个包含Id 1到4的4条记录的主表

然后我有一个事务表来维护一个记录与另一个记录的兼容性

Record1    Record2    IsCompatible
1          2          True
1          3          True
4          1          False
2          3          False
4          2          True
3          4          True

只有一条记录具有相同的Record1 / Record2组合,但在这些记录中,确定给定记录是否保持为Record1或Record2的逻辑取决于设置兼容性时源记录的内容。因此,任何记录都可以随时进行。

从这里我想输出一个看起来像这样的记录集:

RecordID    CompatabilityString
1           Null, True, True, False
2           True, Null, False, True
3           True, False, Null, True
4           False, True, True, Null

CompatabilityString以数字顺序返回每个项目与所有其他项目的兼容性,null表示与其自身的关系。

实现这一目标的最佳途径是什么?

干杯

1 个答案:

答案 0 :(得分:1)

首先你应该用它自己联合这个表来获得一个完整的矩阵,然后使用MAX(CASE...)对这个表进行PIVOT:

SELECT X,
       MAX(CASE WHEN Y=1 THEN IsCompatible END) as Y1,
       MAX(CASE WHEN Y=2 THEN IsCompatible END) as Y2,
       MAX(CASE WHEN Y=3 THEN IsCompatible END) as Y3,
       MAX(CASE WHEN Y=4 THEN IsCompatible END) as Y4

FROM
(
    SELECT Record1 as X,Record2 as Y,IsCompatible FROM T
    UNION ALL
    SELECT Record2 as X,Record1 as Y,IsCompatible FROM T
) as T1
GROUP BY X
ORDER BY X

SQLFiddle demo

如果CompatabilityString只需要一列:

SELECT X as RecordID,
       ISNULL(MAX(CASE WHEN Y=1 THEN IsCompatible END),'NULL')+
       ','+       
       ISNULL(MAX(CASE WHEN Y=2 THEN IsCompatible END),'NULL')+
       ','+       
       ISNULL(MAX(CASE WHEN Y=3 THEN IsCompatible END),'NULL')+
       ','+       
       ISNULL(MAX(CASE WHEN Y=4 THEN IsCompatible END),'NULL')
       as CompatabilityString 


FROM
(
    SELECT Record1 as X,Record2 as Y,IsCompatible FROM T
    UNION ALL
    SELECT Record2 as X,Record1 as Y,IsCompatible FROM T
) as T1
GROUP BY X
ORDER BY X

SQLFiddle demo

UPD:以下是针对可变维度的第二个查询。在这种情况下,FOR XML PATH用于制作以逗号分隔的列表:

;WITH T1 AS
(
    SELECT Record1 as X,Record2 as Y,IsCompatible FROM T
    UNION ALL
    SELECT Record2 as X,Record1 as Y,IsCompatible FROM T
) 

SELECT DISTINCT X,
  STUFF(
         (SELECT ',' + ISNULL(IsCompatible,'NULL')
          FROM (SELECT DISTINCT X as Y FROM T1) as Tbase
          LEFT JOIN T1 AS T2
               ON TBase.Y=T2.Y AND T1.X = T2.X
          ORDER BY TBase.Y
          FOR XML PATH ('')
          )
          , 1, 1, '')  AS COMPATABILITYSTRING
FROM T1
ORDER BY X

SQLFiddle demo