【问题标题】:SQL Server retrieving multiple columns with rank 1SQL Server 检索具有排名 1 的多个列
【发布时间】:2017-01-22 03:16:04
【问题描述】:

我会尽量清楚地描述我的问题。

我有一个包含 1000 个唯一客户的数据集,例如 ##temp1。

我有另一个数据集,其中包含过去 7 年中来自 ##temp1 的 1000 个客户的相关信息。让我们将此数据集称为##temp2。我感兴趣的第二个数据集(##temp2)中有 6 个特定列,我们将它们称为 A、B、C、D、E、F 列。仅供参考,A、C、E 列包含的信息是浮点数据类型(2012、2013、2014..)中某种形式的年份,B、D、F 列保存的信息是浮点数据类型中某种形式的评级(1,2,3,..upto 5) . year 和 rating 列都有 NULL 值,我现在已将其转换为 0。

我的最终目标是创建一个报告,其中包含 ##temp1 中 1000 个客户的信息,这样每一行都应包含以下形式的信息,

ClientID | ClientName | ColA_Latest_Year1 | ColB_Corresponding_Rating_Year_1 | ColC_Latest_Year2 | ColD_Corresponding_Rating_Year_2 | ColE_Latest_Year3 | ColF_Corresponding_Rating_Year3.

ColA_Latest_Year1 应保存数据集 ##temp2 中该特定客户的最新年份,ColB_Corresponding_Rating_Year_1 应保存与从 A 列中提取的年份相对应的 B 列评级。其他列也是如此。

到目前为止,我采取的方法是,

  1. 根据需要创建##temp1
  2. 根据需要创建##temp2
  3. ##temp1 LEFT JOIN ##temp2 在客户端 ID 上检索 ##temp1 中所有客户端的年份和评级信息,并将所有这些信息放入 ##temp3##temp3 中的每个客户都会有多行,因为 ##temp3 中的数据是多年的。
  4. 按client_ids对年份列(B,D,F)分区进行排序,放入##temp4

我现在的东西是这样的,

Rnk_A | Rnk_C | Rnk_F | ColA | ColB | ColC | ColD | ColE | ColF | Client_id | Client_name
2     |    1  |    1  |   0  |  0   |   0  |   0  |  2014 |  1  |   111 | 'ABC'
1     |    2  |    1  | 2012 |  1   |   0  |   0  |  0    |  0  |   111 | 'ABC'

我的目标是

Rnk_A | Rnk_C | Rnk_F | ColA | ColB | ColC | ColD | ColE | ColF | Client_id | Client_name
1     |  1    |   1   |  2012|  1   |  0   |  0   |  2014|  1   | 111 | 'ABC'

感谢任何帮助。

【问题讨论】:

  • "year 和 rating 列都有 NULL 值,我现在已将其转换为 0" 不要那样做! NULL0 根本不同。如果您任意将一个映射到另一个,您将丢失信息,因为您无法再区分这两个 不同 案例。 (请注意,这是一般性建议,您可能会在您的特定情况下侥幸逃脱 - 但是您很幸运。不要养成坏习惯,因为真的:你没有'不需要这样做 只要你只是简单地正确处理 NULL。)
  • 您的 A、C、E 列是否有任何重复的每个客户。对于您的解决方案,这是一个非常重要的考虑因素。 (并且 PS:一般来说,您应该显示您尝试过的查询不太有效。)

标签: sql sql-server-2008


【解决方案1】:

此答案假定您在 A、C、E 列中每个客户没有任何重复项。如果确实有重复项,则需要找到一种方法来区分它们并进行必要的更改。

您在尝试中未能克服的障碍(如上所述)是您尝试从 temp1 加入到 temp2 仅一次 查找可能来自temp2 的 3 个不同行的查找信息。这不能像你希望的那样工作。您必须对每对 [A,B] [C,D] 和 [E,F] 执行单独的连接。下面演示了一个使用 CTE 导出每对查找数据的解决方案。

/********* Prepare sample tables and data ***********/
declare @t1 table (
    ClientId int,
    ClientName varchar(50)
)

declare @t2 table (
    ClientId int,
    ColA datetime,
    ColB float,
    ColC datetime,
    ColD float,
    ColE datetime,
    ColF float
)

insert into @t1
select  1, 'Client 1' union all
select  2, 'Client 2' union all
select  3, 'Client 3' union all
select  4, 'Client 4'

insert into @t2
select  1, '20001011', 1, '20010101', 7, '20130101', 14 union all
select  1, '20040101', 4, '20170101', 1, '20120101', 1 union all
select  1, '20051231', 0, '20020101', 15, '20110101', 1 union all
select  2, '20060101', 2, NULL, 15, '20110101', NULL union all
select  2, '20030101', 3, NULL, NULL, '20100101', 17 union all
select  3, NULL, NULL, '20170101', 42, NULL, NULL

--select  * from @t1
--select  * from @t2

/********* Solution ***********/
;with MaxA as (
    select  ROW_NUMBER() OVER (PARTITION BY t2.ClientId ORDER BY t2.ColA DESC) rn,
    t2.ClientId, t2.ColA, t2.ColB
    from    @t2 t2
    --where   t2.ColA is not null and t2.ColB is not null
), MaxC as (
    select  ROW_NUMBER() OVER (PARTITION BY t2.ClientId ORDER BY t2.ColC DESC) rn,
    t2.ClientId, t2.ColC, t2.ColD
    from    @t2 t2
    --where   t2.ColC is not null and t2.ColD is not null
), MaxE as (
    select  ROW_NUMBER() OVER (PARTITION BY t2.ClientId ORDER BY t2.ColE DESC) rn,
    t2.ClientId, t2.ColE, t2.ColF
    from    @t2 t2
    --where   t2.ColE is not null and t2.ColF is not null
)
select  t1.ClientId, t1.ClientName, a.ColA, a.ColB, c.ColC, c.ColD, e.ColE, e.ColF
from    @t1 t1
        left join MaxA a on
            a.ClientId = t1.ClientId
        and a.rn = 1
        left join MaxC c on
            c.ClientId = t1.ClientId
        and c.rn = 1
        left join MaxE e on
            e.ClientId = t1.ClientId
        and e.rn = 1

如果您运行此程序,您可能会注意到 C 和 F 列中客户端 2 的一些特殊结果。这是因为(根据您的问题)可能存在一些 NULL 值。 ColC 日期为“未知”,ColF 评级为“未知”。

我的解决方案保留NULL 值,而不是将它们转换为零。如果您愿意,这允许您明确处理它们。我在上述查询中注释掉了可用于在必要时忽略 NULL 日期和评级的行。

【讨论】:

  • 谢谢克雷格!这正是我一直在寻找的。为了回答您的问题,我的##temp1 或您的情况下的 t1 中没有任何重复项。我的##temp1 中有1000 个唯一客户。但是,我的 ##temp2 中存在这些客户的多条记录,因为 ##temp2 保存了这些客户过去 7 年的数据。
猜你喜欢
  • 2013-10-16
  • 2017-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
  • 2017-10-06
相关资源
最近更新 更多