根据另一个 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_number
window函数
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 来自另一个结果集的列(在本例中为客户端列表)。您可以为此使用 TOP
和 ORDER BY
。
CROSS
和 OUTER
之间的区别类似于 INNER
和 LEFT
(连接)。
假设我有 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_number
window函数
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 来自另一个结果集的列(在本例中为客户端列表)。您可以为此使用 TOP
和 ORDER BY
。
CROSS
和 OUTER
之间的区别类似于 INNER
和 LEFT
(连接)。