【问题标题】:Returning nth value from results or NULL从结果中返回第 n 个值或 NULL
【发布时间】:2014-10-13 09:20:32
【问题描述】:

我正在使用查询

(select top (1) a.Description from ClientContactAttributes cca inner join Attributes a on a.AttributeId = cca.AttributeId where cca.ClientContactId = cc.ClientContactId order by cca.AttributeId desc) as Attribute1,
(select top (1) Description from (select top (2) a.Description, cca.AttributeId from ClientContactAttributes cca inner join Attributes a on a.AttributeId = cca.AttributeId where cca.ClientContactId = cc.ClientContactId order by cca.AttributeId desc) q order by q.AttributeId asc) as Attribute2,
(select top (1) Description from (select top (3) a.Description, cca.AttributeId from ClientContactAttributes cca inner join Attributes a on a.AttributeId = cca.AttributeId where cca.ClientContactId = cc.ClientContactId order by cca.AttributeId desc) q order by q.AttributeId asc) as Attribute3,
etc

获取针对记录添加的属性列表。目前,如果 any 属性已添加到该记录,它会多次返回最终结果,但理想情况下,如果该属性不存在,我希望返回 NULL。

例如,而不是返回

Attribute1   Attribute2  Attribute3   Attribute4
Bed          Bath        Beyond       Beyond
Bed          Bed         Bed          Bed

我宁愿它回来

Attribute1   Attribute2  Attribute3   Attribute4
Bed          Bath        Beyond       NULL
Bed          NULL        NULL         NULL

最好的方法是什么?

【问题讨论】:

    标签: sql sql-server-2008


    【解决方案1】:

    使用ROW_NUMBER()。首先为每条记录分配一个行号:

    SELECT  cca.ClientContactId,
            a.Description,
            RowNumber = ROW_NUMBER() OVER(PARTITION BY cca.ClientContactId 
                                            ORDER BY a.AttributeId)
    FROM    ClientContactAttributes AS cca
            INNER JOIN Attributes AS a
                ON a.AttributeId = cca.AttributeId;
    

    然后你可以使用这个RowNumber 列来PIVOT 你的数据:

    WITH Data AS
    (   SELECT  cca.ClientContactId,
                a.Description,
                RowNumber = ROW_NUMBER() OVER(PARTITION BY cca.ClientContactId 
                                                ORDER BY a.AttributeId)
        FROM    ClientContactAttributes AS cca
                INNER JOIN Attributes AS a
                    ON a.AttributeId = cca.AttributeId
    )
    SELECT  pvt.ClientContactID,
            Attribute1 = pvt.[1],
            Attribute2 = pvt.[2],
            Attribute3 = pvt.[3],
            Attribute4 = pvt.[4]
    FROM    Data
            PIVOT
            (   MAX(Description)
                FOR RowNumber IN ([1], [2], [3], [4])
            ) AS pvt;
    

    编辑

    如果你不明白,那么我没有正确回答!我坚信这句谚语“授人以鱼,养其一日;授人以渔,养其一生”

    如果你的两个表中有以下数据:

    属性'

    AttributeId | Description
    ------------+---------------
        1       |     Bed          
        2       |     Bath        
        3       |    Beyond 
    

    ClientContactAttributes

    ClientContactID | AttributeId
    ----------------+---------------
           1        |    1
           1        |    2
           1        |    3
           2        |    1
    

    运行以下:

    SELECT  cca.ClientContactId,
            a.Description,
            RowNumber = ROW_NUMBER() OVER(PARTITION BY cca.ClientContactId 
                                            ORDER BY a.AttributeId)
    FROM    ClientContactAttributes AS cca
            INNER JOIN Attributes AS a
                ON a.AttributeId = cca.AttributeId;
    

    会给你:

    ClientContactID | Description | RowNumber
    ----------------+-------------+-----------
           1        |     Bed     |     1
           1        |     Bath    |     2
           1        |    Beyond   |     3
           2        |     Bed     |     1
    

    ROW_NUMBER() 函数只是为每个组分配一个唯一编号(在PARTITION BY 子句中定义),该编号由ORDER BY 子句确定。所以这一行:

    ROW_NUMBER() OVER(PARTITION BY cca.ClientContactId ORDER BY a.AttributeId)
    

    本质上是说,对于 cca.ClientContactId 的每个唯一值,我想要一个唯一的数字,从 1 开始,其中 attributeId 的最低值接收 1 并且数字从那里递增:

    PIVOT 函数很像 excel 数据透视表,您希望在其中将行转换为列。它有两个基本部分,我将在这里倒推。第一部分是FOR 子句:

    FOR RowNumber IN ([1], [2], [3], [4])
    

    这是您想要转换为行的RowNumber 列中的值。列名将对应于提供的值。第二部分(第一个逻辑阅读)定义将进入这些新创建的列的值。这必须是一个聚合函数,在这种情况下是:

    MAX(Description)
    

    由于您已经知道 RowNumber 对于每个 ClientContactId 都是唯一的,因此聚合函数(PIVOT 所需的)实际上是没有意义的,因为只有一个描述值要聚合。

    希望这更有意义。

    【讨论】:

    • 这看起来棒极了,虽然我还不打算假装我完全理解它!只有一个错字 - 在 a.description 之后,你有一个 double ,
    • 现在确实更有意义了,谢谢! (顺便说一下,在第二个查询中还有一个)如果我想加入更多记录,那么最有效的方法是什么?在初始查询中添加连接,然后对其进行透视,或者将它们连接到透视数据?
    • 它在效率方面可能不会有太大的不同。无论子查询和连接的顺序如何,SQL Server 往往非常擅长重组查询。如果不确定,请尝试这两种方法并比较运行时间和执行计划
    猜你喜欢
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 2010-11-15
    • 2020-06-24
    • 1970-01-01
    • 2020-04-23
    相关资源
    最近更新 更多