从结果返回第n个值或NULL

时间:2014-10-13 09:20:33

标签: sql sql-server-2008

我正在使用查询

(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

获取针对记录添加的属性列表。目前,如果任何属性已添加到该记录,它会多次返回最终结果,但理想情况下,如果该属性不存在,我希望返回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

这样做的最佳方式是什么?

1 个答案:

答案 0 :(得分: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;

修改

如果你不明白,那么我没有正确回答!我坚信谚语"给一个人一条鱼,你喂他一天;教一个人钓鱼,你喂他一辈子"

如果您的两个表格中包含以下数据:

<强>属性&#39;

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`所需的)实际上没有意义,因为只有一个值可用于聚合。< / p>

希望这更有意义。