查看差异表

Make a view of a difference table

提问人:steve mcqueen 提问时间:11/5/2023 最后编辑:Dale Ksteve mcqueen 更新时间:11/6/2023 访问量:72

问:

让我们想象两个表 - T_Name、T_nameAttributes

T_name

名字 名称 ID
萨拉 2
马修 3

T_nameAttributes

名称 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 and nameID = 2

Sara, 3, Red Apple

每天,这些值都保存到相同的表架构中,并带有一个额外的“日期”列,在这里一切都很好,我可以轻松地检索请求日期的值

这里的问题 - 我想节省数据库空间并仅存储更改的值,所以我的日志表现在看起来像这样:(这部分已经完成)

T_NameLog

日期 名字 名称 ID
2023-01-01 萨拉 2
2023-10-05 莎拉 2 // 名称已更改

T_nameAttributesLog

日期 属性 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 and nameID = 2

预期结果:

日期 名字 属性
2023-10-02 萨拉 红苹果
2023-10-03 萨拉 红苹果
2023-10-04 萨拉 青苹果
2023-10-05 莎拉 青苹果
sql sql-server sql-server-2012

评论

0赞 Zohar Peled 11/5/2023
我不太确定这里的问题是什么 - 是如何仅记录更改,还是如何选择日志表中未出现的日期?
0赞 Thorsten Kettner 11/5/2023
附带说明:第一个查询当然也会选择 Matthew,因为这就是外部连接的全部内容。
0赞 steve mcqueen 11/5/2023
@ThorstenKettner,我的错误,但这与主要问题无关,Matthew在这里只是为了代表数据组织
0赞 steve mcqueen 11/5/2023
@ZoharPeled第二个,对不起,解释不清楚

答:

0赞 Thorsten Kettner 11/5/2023 #1

首先为每个日期生成一行。然后与子句一起使用以获取表的最新行。我没有只查找一个名称和一个属性,而是编写了我的查询,以便它可以找到所有名称和属性。这是通过与 .CROSS APPLYTOPTOP (1) WITH TIESORDER BY RANK()

如果只想使用一个名称或仅使用一个属性,只需注释掉子句中的 ID 条件即可。(但在这种情况下,没有从句和仅 .WHERETOP (1)WITH TIESORDER 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
cross 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
cross 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;

演示:https://dbfiddle.uk/WyhGYzqy

评论

0赞 steve mcqueen 11/5/2023
非常感谢!我会试试的