在SQL Server中“旋转”非聚合数据

时间:2010-11-19 14:34:16

标签: sql-server-2005 pivot sql

这将是我在这里发布的第一个问题,因此请原谅任何无意识的董事会礼仪失误。

在我目前的项目中,我采用了一个非规范化的大型表,并将其分解为四个独立的规范化表。我接触到这个板的最终目标是创建一个模仿非规范化表以便向后兼容的视图。

为了提供我的场景的简化快照,我正在尝试做的关键在于两个表:

ASSOC_ROLE          ASSOCIATE
----------          ----------
assoc_id (fk)       assoc_id (pk)
role_id  (fk)       last_name
org_nbr  (fk)

所以,如果我发出以下查询...

SELECT Assoc_Role.org_nbr, Assoc_Role.assoc_id, Associate.last_name, Assoc_Role.role_id
FROM Assoc_Role INNER JOIN
     Associate ON Assoc_Role.assoc_id = Associate.assoc_id
WHERE Assoc_Role.org_nbr = '1AA'

...我得到以下结果集

org_nbr     assoc_id     last_name     role_id
-------     --------     ---------     -------
1AA         1447         Cooper        1
1AA         1448         Collins       3
1AA         1448         Collins       4
1AA         1448         Collins       5
1AA         1449         Lynch         6

最终,我想构建的视图看起来像这样:

org_nbr   role1_ID   role1_name   role2_ID   role2_name   role3_ID   role3_name   role4_ID   role4_name   role5_ID   role5_name   role6_ID   role6_name
-------   --------   ----------   --------   ----------   --------   ----------   --------   ----------   --------   ----------   --------   ----------
1AA       1447       Cooper       NULL       NULL         1448       Collins      1448       Collins      1448       Collins      1449       Lynch

我最初的想法是尝试使用PIVOT命令,但我的理解是PIVOT需要某种聚合,这不适合我的场景。我也在SELECT子句中使用了CASE命令,但它并没有将我的结果集压缩到一个记录。

希望有人可以阐明如何实现这一目标。如果有人需要更多信息,请告诉我。谢谢!

苏格兰人

2 个答案:

答案 0 :(得分:2)

要获取基本的编号角色数据,我们可以从

开始
SELECT
    org_nbr
    , r1.assoc_id   role1_ID
    , r1.last_name  role1_name
    , r2.assoc_id   role2_ID
    , r2.last_name  role2_name
    , r3.assoc_id   role3_ID
    , r3.last_name  role3_name
    , r4.assoc_id   role4_ID
    , r4.last_name  role4_name
    , r5.assoc_id   role5_ID
    , r5.last_name  role5_name
    , r6.assoc_id   role6_ID
    , r6.last_name  role6_name
FROM
    ASSOC_ROLE ar
    LEFT JOIN ASSOCIATE r1 ON ar.role_id = 1 AND ar.assoc_id = r1.assoc_id
    LEFT JOIN ASSOCIATE r2 ON ar.role_id = 2 AND ar.assoc_id = r2.assoc_id
    LEFT JOIN ASSOCIATE r3 ON ar.role_id = 3 AND ar.assoc_id = r3.assoc_id
    LEFT JOIN ASSOCIATE r4 ON ar.role_id = 4 AND ar.assoc_id = r4.assoc_id
    LEFT JOIN ASSOCIATE r5 ON ar.role_id = 5 AND ar.assoc_id = r5.assoc_id
    LEFT JOIN ASSOCIATE r6 ON ar.role_id = 6 AND ar.assoc_id = r6.assoc_id

这将为每个org_nbr的每个role_id提供一个包含数据的单独行!这不是我们想要的 - 所以我们需要GROUP BY org_nbr。但是,我们需要GROUP BY或聚合SELECT列表中的每一列!然后诀窍是提出一个聚合函数,它将安抚SQL Server 给我们想要的结果。在这种情况下,MIN将完成这项工作:

SELECT
    org_nbr
    , MIN(r1.assoc_id)   role1_ID
    , MIN(r1.last_name)  role1_name
    , MIN(r2.assoc_id)   role2_ID
    , MIN(r2.last_name)  role2_name
    , MIN(r3.assoc_id)   role3_ID
    , MIN(r3.last_name)  role3_name
    , MIN(r4.assoc_id)   role4_ID
    , MIN(r4.last_name)  role4_name
    , MIN(r5.assoc_id)   role5_ID
    , MIN(r5.last_name)  role5_name
    , MIN(r6.assoc_id)   role6_ID
    , MIN(r6.last_name)  role6_name
FROM
    ASSOC_ROLE ar
    LEFT JOIN ASSOCIATE r1 ON ar.role_id = 1 AND ar.assoc_id = r1.assoc_id
    LEFT JOIN ASSOCIATE r2 ON ar.role_id = 2 AND ar.assoc_id = r2.assoc_id
    LEFT JOIN ASSOCIATE r3 ON ar.role_id = 3 AND ar.assoc_id = r3.assoc_id
    LEFT JOIN ASSOCIATE r4 ON ar.role_id = 4 AND ar.assoc_id = r4.assoc_id
    LEFT JOIN ASSOCIATE r5 ON ar.role_id = 5 AND ar.assoc_id = r5.assoc_id
    LEFT JOIN ASSOCIATE r6 ON ar.role_id = 6 AND ar.assoc_id = r6.assoc_id
GROUP BY
    org_nbr

输出:

org_nbr    role1_ID    role1_name role2_ID    role2_name role3_ID    role3_name role4_ID    role4_name role5_ID    role5_name role6_ID    role6_name
---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ----------
1AA        1447        Cooper     NULL        NULL       1448        Collins    1448        Collins    1448        Collins    1449        Lynch
Warning: Null value is eliminated by an aggregate or other SET operation.

当然,如果最大role_id增加......

,这将无法实现

答案 1 :(得分:2)

如果可以的话,我强烈建议在常规代码(c#,vb,无论如何)中进行这种类型的旋转。

SQL Server中的PIVOTing有很多缺点。首先,超过7或8项的任何内容都会大大增加查询所需的时间。其次,它要求你做动态sql或提前知道所有潜在的id。第三,难以维持。

AakashM的答案中存在同样的问题。

我们尝试了很多不同的方法来在纯SQL环境中完成这项工作。对于枢轴非常有限的小型数据集,它可以正常工作。但是,您已经拥有的角色ID数量超出了它。

相反,只需抓住数据并用您喜欢的语言创建您需要的表格。此时要么将数据放入不同的sql表中,要么将其发送到需要的位置。