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

Tsql 如何开发t-sql子查询,使每个子查询只选择一条记录?,tsql,sql-server-2008,null,subquery,having,Tsql,Sql Server 2008,Null,Subquery,Having,我正在使用SSMS 2008,试图只选择一行/客户端。我需要选择以下列:客户端名称、结束日期和程序。有些客户端只有一个客户端行。但其他人有多重选择 对于具有多行的客户端,它们通常具有不同的结束日期和程序。例如: CLIENT PROGRAM END_DATE a b c a d e a f g h d

我正在使用SSMS 2008,试图只选择一行/客户端。我需要选择以下列:客户端名称、结束日期和程序。有些客户端只有一个客户端行。但其他人有多重选择

对于具有多行的客户端,它们通常具有不同的结束日期和程序。例如:

CLIENT       PROGRAM        END_DATE
a            b              c
a            d              e
a            f              g
h            d              e
h            f              NULL
这是实际数据的真实简化版本。正如您将看到的,不同的客户端可以在同一个程序d中。但是同一客户端不能在同一程序中多次出现

还有一件棘手的事情是,结束日期可以为NULL,所以当我尝试选择那些行>1的客户机时,我添加了一个HAVING语句>1。但这消除了我所有的空结束日期行

总之,我希望每个客户机有一行。因此,只有一行的客户机总数+以上列出的客户机符合以下标准:

仅选择结束日期最大或为空的行。在大多数情况下,这些客户端的结束日期为空。
我怎样才能用尽可能少的逻辑实现这一点

在SQLServer2005及更高版本上,您可以使用一个公共表表达式CTE,并结合行数和分区函数。这个CTE将按照一个标准对您的数据进行分区—在您的案例中,是按客户机,为每个单独的客户机创建一个分区。然后,行_编号将根据另一个条件对每个分区进行编号(这里我创建了一个DATETIME),并从1开始为每个分区分别分配编号

所以在本例中,按DATETIME DESC排序,最新的行编号为1,这就是我在从CTE中选择时使用的事实。我在这里使用ISNULL函数为那些具有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)

在SQLServer2005及更高版本上,您可以使用一个公共表表达式CTE,并结合行数和分区函数。这个CTE将按照一个标准对您的数据进行分区—在您的案例中,是按客户机,为每个单独的客户机创建一个分区。然后,行_编号将根据另一个条件对每个分区进行编号(这里我创建了一个DATETIME),并从1开始为每个分区分别分配编号

所以在本例中,按DATETIME DESC排序,最新的行编号为1,这就是我在从CTE中选择时使用的事实。我在这里使用ISNULL函数为那些具有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)

我假设结束日期为空的行优先于maxend\u日期。但是,如果一个客户端有两个不同程序的NULL end_日期,那么应该返回什么,因为您只希望每个客户端返回一行?我假设end_日期为NULL的行优先于maxend_日期。但是,如果一个客户机有两个不同程序的空结束日期,那么应该返回什么?因为您只希望每个客户机返回一行?谢谢Marc,我想在有给定结束日期的行中选择空行。@salvantionsishere:好的,在这种情况下,只需将ISNULL调用中的日期替换为991231-12月31日,9999-然后将首先显示带有NULL的行。超级!谢谢马克;这正是我需要的!谢谢Marc,我想在具有给定结束日期的行中选择空行。@salvantionsishere:好的,在这种情况下,只需将ISNULL调用中的日期替换为99991231-9999年12月31日-然后空行将首先出现。超级!谢谢马克;这正是我需要的!