根据另一个 table 中的数据,仅获取每个 clientid 每行每个非唯一列的前 1 个

Get only the top 1 per non-unique column per row, per clientid, based on data in another table

假设我有 table ClientStatusHistory

这包含特定 Client.

状态更改的历史记录

table 看起来像这样:

(日期格式:DD/MM/YYYY)

客户端状态历史:

(有个自增PK列叫ID)

ClientID | StatusID | DateStarted | DateEnded
1        | 5        | 01/01/2000  | 01/01/2019
1        | 7        | 01/01/2019  | 11/01/2019
1        | 8        | 11/01/2019  | Null
2        | 5        | 01/01/2000  | 01/01/2019
2        | 7        | 01/01/2019  | 11/01/2019
2        | 8        | 11/01/2019  | Null

所有反映其当前状态的 rows/records 在其 DateEnded 列中都为 Null。

我如何拉取他们当前状态之前的所有状态,并将其插入临时 table?

我正在考虑使用 top 1,但它只会以我正在使用的方式提取 1 条记录:

select top 1 clientid, statusid, datestarted, dateended
from ClientStatusHistory
where
dateended is not null
order by id desc 

这将使用 desc 从最近到最旧的顺序对它们进行排序,然后在我们忽略空值时拉出当前处于活动状态之前的那个。

我如何扩展上述查询以从 ClientStatusHistory 中提取所有行,其中状态是具有 null DateEnded 字段的行之前的行,对于每个 ClientID

一种方法使用 window 函数。但我认为 join 也有效:

select csh_prev.*
from ClientStatusHistory csh join
     ClientStatusHistory csh_prev
     on csh.clientid = csh_prev.clientid and
        csh.datestarted = csh_prev.dateended
where csh.dateended is null;

具有window个功能:

select csh.*
from (select csh.*,
             lead(dateended) over (partition by clientid order by datestarted) as next_dateended
      from ClientStatusHistory csh 
     ) csh
where next_dateended is null;

你想要 row_number() :

select top (1) with ties cs.*
from ClientStatusHistory cs
where dateended is not null
order by row_number() over (partition by ClientID  order by id desc);

使用row_numberwindow函数

select * from    
(
select *,row_number() over(partition by ClientID order by DateEnded desc) rn
from t
) where t.rn=1

另一种使用 CROSS/OUTER APPLY 的解决方案:

;WITH AvailableClients AS
(
    SELECT DISTINCT C.ClientID FROM ClientStatusHistory AS C
)
SELECT
    C.ClientID,
    T.*
FROM
    AvailableClients AS C
    OUTER APPLY (
        SELECT TOP 1
            H.*
        FROM
            ClientStatusHistory AS H
        WHERE
            C.ClientID = H.CLientID AND
            H.DateEnded IS NOT NULL
        ORDER BY
            H.DateEnded DESC) AS T

CROSS/OUTER APPLY 基本上是一个“在旅途中结果集 函数,您可以编写它给您机会到 link 来自另一个结果集的列(在本例中为客户端列表)。您可以为此使用 TOPORDER BY

CROSSOUTER 之间的区别类似于 INNERLEFT(连接)。