1

我正在使用 SSMS 2008,试图只选择一行/客户端。我需要选择以下列:client_nameend_dateprogram。有些客户只有一个客户行。但其他人有多个。

对于具有多行的客户端,它们通常具有不同的end_dateprogram。例如:

CLIENT       PROGRAM        END_DATE
a            b              c
a            d              e
a            f              g
h            d              e
h            f              NULL

这是实际数据的真正简化版本。正如您将看到的,不同的客户端可以在同一个程序(“d”)中。但是同一个客户不能多次出现在同一个程序中。

还有一个棘手的问题是它end_date可以是 NULL,所以当我尝试选择那些 > 1 行的客户端时,我添加了一个 HAVING 语句 > 1。但这消除了我所有的 NULLEnd_date行。

总而言之,我想要每个客户一行。因此,总共只有一行的客户 + 上面列出的具有以下条件的客户:

  • 仅选择End_date最大或 NULL 的行。(在大多数情况下end_date,这些客户端的值为 null)。

我怎样才能用尽可能少的逻辑来实现这一点?

4

1 回答 1

4

在 SQL Server 2005 及更高版本上,您可以将公用表表达式 (CTE) 与ROW_NUMBER()andPARTITION BY函数结合使用。此 CTE 将按一个标准“分区”您的数据 - 在您的情况下Client,为每个单独的客户端创建一个“分区”。然后ROW_NUMBER()将按另一个标准对每个分区进行编号 - 这里我创建了一个DATETIME- 并为每个分区分别分配从 1 开始的数字。

所以在这种情况下,按 排序DATETIME DESC,最新的行编号为 1 - 这就是我从 CTE 中选择时使用的事实。我在这里使用该ISNULL()函数来为那些具有 NULL 的行分配end_date一些任意值以“按顺序排列它们”。我不太确定我是否正确理解了您的问题:您是否想选择 NULL 行而不是具有给定的行end_Date,或者您是否想优先考虑现有end_Date值而不是 NULL?

这将为每个客户端选择最近的行(对于数据的每个“分区”):

DECLARE @clients TABLE (Client CHAR(1), Program CHAR(1), END_DATE DATETIME)

INSERT INTO @clients 
VALUES('a', 'b', '20090505'),
('a', 'd', '20100808'),
('a', 'f', '20110303'),
('h', 'd', '20090909'),
('h', 'f', NULL)

;WITH LatestData AS
(
   SELECT Client, Program, End_Date,
       ROW_NUMBER() OVER(PARTITION BY CLient ORDER BY ISNULL(End_Date, '99991231') DESC) AS 'RowNum'
    FROM @clients
)
SELECT Client, Program, End_Date
FROM LatestData 
WHERE RowNum = 1

结果为:

Client  Program  End_Date
   a       f     2011-03-03
   h       f     (NULL)
于 2011-09-17T22:19:40.637 回答