如何开发t-sql子查询,每个只选择一条记录?

时间:2011-09-17 21:57:23

标签: tsql sql-server-2008 null subquery having

我正在使用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语句>但是这消除了我的所有NULL End_date行。

总而言之,我希望每个客户端有一行。因此,那些只有一行的客户+上面列出的客户具有以下标准:

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

如何以尽可能少的逻辑实现这一目标?

1 个答案:

答案 0 :(得分:4)

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

因此,在这种情况下,按DATETIME DESC排序,最新的行编号为1 - 这是我从CTE中选择时使用的事实。我在这里使用ISNULL()函数将具有NULL end_date某些任意值的行分配给“按顺序获取它们”。我不太确定我是否正确理解了您的问题:您是否想要选择具有给定end_Date的NULL行,或者您是否希望优先于NULL上的现有end_Date值?

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

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)