让我们想象两个表 - T_Name、T_nameAttributes
T_名称
姓名 | 姓名ID |
---|---|
莎拉 | 2 |
马修 | 3 |
T_name属性
姓名ID | 属性ID | 价值 |
---|---|---|
2 | 3 | 红苹果 |
2 | 5 | 20 美元 |
最初从他们那里检索数据看起来像这样
select *
from T_name
left join T_nameAttributes
on T_name.NameID = T_nameAttributes.NameID
and AttributeID = 3
Sara, 3, Red Apple
每天,这些值都会保存到带有附加“日期”列的同一表模式中,这里一切都很好,我可以轻松地在请求的日期检索值
这里的问题 - 我想节省数据库空间并仅存储更改的值,所以我的日志表现在看起来像这样:
T_姓名日志
日期 | 姓名 | 姓名ID |
---|---|---|
2023-01-01 | 莎拉 | 2 |
2023-10-05 | 莎拉 | 2 // 名称已更改 |
T_name属性日志
日期 | 属性ID | 姓名ID | 价值 |
---|---|---|---|
2023-01-01 | 3 | 2 | 红苹果 |
2023-10-04 | 3 | 2 | 青苹果 // 值改变了 |
2023-01-01 | 5 | 2 | 20 美元 |
2023-02-12 | 5 | 2 | 0 美元 |
2023-10-09 | 5 | 2 | 70 美元 |
问题:两个表都可以在随机日期更改其值,我想检索一个连接表,其中的行基于一个月中的每一天
Select date, name, value
from T_NameLog
left join T_nameAttributesLog <...>
where date between '2023-10-02' and '2023-10-05'
and AttributeID = 3
预期结果:
日期 | 名字 | 属性 |
---|---|---|
2023-10-02 | 莎拉 | 红苹果 |
2023-10-03 | 莎拉 | 红苹果 |
2023-10-04 | 莎拉 | 青苹果 |
2023-10-05 | 莎拉 | 青苹果 |
首先为每个日期生成一行。然后使用
OUTER APPLY
和 TOP
子句来获取表的最新行。我编写了查询,以便它可以查找所有名称和属性,而不是仅查找一个名称和一个属性。这是通过 TOP (1) WITH TIES
与 ORDER BY RANK()
结合完成的。
如果您只需要一个名称或一个属性,只需注释掉
WHERE
子句中的 ID 条件即可。 (但在这种情况下,有 TOP (1)
就足够了,没有 WITH TIES
子句,只有 ORDER BY [Date] DESC
。)
with
days as
(
select cast('2023-10-02' as date) as dt,
cast('2023-10-05' as date) as last_dt
union all
select dateadd(day, 1, dt),
last_dt
from days
where dt < last_dt
)
select days.dt, n.name, na.value
from days
outer apply
(
select top (1) with ties
nl.name,
nl.nameid
from t_namelog nl
where nl.[Date] <= days.dt
-- and nl.nameid = 2
order by rank() over (partition by nl.nameid order by nl.[Date] desc)
) n
outer apply
(
select top (1) with ties
nal.value,
nal.attributeid
from t_nameattributeslog nal
where nal.nameid = n.nameid
and nal.[Date] <= days.dt
-- and nal.attributeid = 3
order by rank() over (partition by nal.attributeid order by nal.[Date] desc)
) na
order by days.dt, n.nameid, na.attributeid;