简体   繁体   English

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

[英]“Pivoting” non-aggregate data in SQL Server

this will be the first question I've posted here so pardon any unintended lapses in board etiquette. 这将是我在这里发布的第一个问题,因此请原谅任何无意识的董事会礼仪失误。

In my current project, I've taken a large, non-normalized table and broken it into four separate, normalized tables. 在我当前的项目中,我采用了一个非规范化的大型表,并将其分解为四个独立的规范化表。 My ultimate goal that I'm reaching out to this board for is to create a view which mimics the non-normalized table for backwards compatibility. 我接触到这个板的最终目标是创建一个模拟非规范化表以便向后兼容的视图。

To provide a simplified snapshot of my scenario, the crux of what I'm trying to do lies in two tables: 为了提供我的场景的简化快照,我正在尝试做的关键在于两个表:

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

So if I issue the following query... 所以,如果我发出以下查询......

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'

...I get the following result set ...我得到以下结果集

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

Ultimately, the view I would like to construct would look something like this: 最终,我想构建的视图看起来像这样:

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

My initial thought was to try to use the PIVOT command, but my understanding is that PIVOT requires some kind of aggregation, and that doesn't fit my scenario. 我最初的想法是尝试使用PIVOT命令,但我的理解是PIVOT需要某种聚合,这不适合我的场景。 I've also played around with the CASE command in the SELECT clause, but it doesn't flatten my result set down to one record. 我也在SELECT子句中使用了CASE命令,但它并没有将我的结果集压缩到一个记录。

Hopefully someone can shed some light on how I can accomplish this. 希望有人可以阐明如何实现这一目标。 Let me know if anyone needs more info. 如果有人需要更多信息,请告诉我。 Thanks! 谢谢!

Scot 苏格兰人

To get the basic numbered-role data, we might start with 要获得基本的编号角色数据,我们可以从中开始

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

BUT this will give us, for each org_nbr , a separate row for each role_id that has data! 但是 ,对于每个org_nbr ,这将为每个具有数据的role_id一个单独的行! Which is not what we want - so we need to GROUP BY org_nbr . 这不是我们想要的 - 所以我们需要GROUP BY org_nbr But then we need to either GROUP BY or aggregate over every column in the SELECT list! 但是,我们需要GROUP BY或聚合SELECT列表中的每一列! The trick then is to come up with an aggregate function that will placate SQL Server and give us the results we want. 接下来的技巧是提出一个聚合函数,它将安抚SQL Server 为我们提供我们想要的结果。 In this case, MIN will do the job: 在这种情况下, 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

Output: 输出:

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.

Of course this will fall short should the maximum role_id increase... 当然,如果最大的role_id增加,这将role_id ......

If you can, I would highly recommend doing this type of pivoting in regular code (c#, vb, whatever). 如果可以,我强烈建议在常规代码(c#,vb,无论如何)中进行这种类型的旋转。

PIVOTing in SQL server has a lot of drawbacks. SQL服务器中的PIVOTing有很多缺点。 First, anything over 7 or 8 items is going to massively increase the amount of time your queries take. 首先,超过7或8项的任何内容都会大大增加查询所需的时间。 Second, it requires you to either do dynamic sql OR to know all the potential id's ahead of time. 其次,它要求你做动态sql或提前知道所有潜在的id。 Third, it will be difficult to maintain. 第三,难以维持。

The same problems exist in AakashM's answer. AakashM的回答也存在同样的问题。

We've tried a lot of different ways to make this work in a pure SQL setting. 我们已经尝试了很多不同的方法来使这个工作在纯SQL设置中。 For small data sets with very limited pivot's it will work just fine. 对于枢轴非常有限的小型数据集,它可以正常工作。 However, the number of Role Id's you already have go beyond it. 但是,您已经拥有的角色ID数量超出了它。

Instead, just grab the data and in your favorite language create the table you need. 相反,只需抓住数据并用您喜欢的语言创建您需要的表格。 At that point either put the data into a different sql table or send it along to where ever it needs to go. 此时要么将数据放入不同的sql表中,要么将其发送到需要的位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM