SQL:如何最好地查询历史表以创建特定日期的快照概览
Posted
技术标签:
【中文标题】SQL:如何最好地查询历史表以创建特定日期的快照概览【英文标题】:SQL: How to best query a history table to create a snapshot overview of a specific date 【发布时间】:2018-03-25 12:16:06 【问题描述】:我对 SQL 和数据库结构相对较新,并且有一个问题是最好的方法是什么。
我有对象的历史变化数据,有时需要将其转换为特定日期的快照。
数据示例:
ID Value UpdateDate
1 4 2017-01-01
2 4 2017-01-03
3 4 2017-01-03
1 7 2017-01-04
2 5 2017-01-08
3 5 2017-01-10
2 8 2017-01-11
我希望能够在任何给定日期创建所有对象的完整概览的快照。例如:
Current Date: 2017-01-01 | Current Date: 2017-01-04
ID Value LastUpdateDate | ID Value LastUpdateDate
|
1 4 2017-01-01 | 1 7 2017-01-04
| 2 4 2017-01-03
| 3 4 2017-01-03
__________________________________________________________________________________
|
Current Date: 2017-01-08 | Current Date: 2017-01-12
ID Value LastUpdateDate | ID Value LastUpdateDate
|
1 7 2017-01-04 | 1 7 2017-01-04
2 5 2017-01-08 | 1 8 2017-01-10
3 4 2017-01-03 | 1 5 2017-01-11
我创建了以下 SQL 查询来创建这些表。但我想知道这是否是最“有效”的方法?实际上我的表非常大,有时每个对象类型有 200K-300K 唯一对象,每天有几千次更新(不是每个对象,但每天只有几千行添加到历史表中,所以它的大小正在增长快)。
SQL 查询:
SELECT * INTO @CurrentOverviewTableName
FROM @HistoryTableName
INNER JOIN (
SELECT ID AS ID_T, MAX(LastUpdateDate) AS LastUpdateDate
FROM @HistoryTableName
WHERE LastUpdateDate <= @OverviewDate
GROUP BY ID
) ts
ON S@HistoryTableName.ID = ts.ID_T AND @HistoryTableName.LastUpdateDate = ts.LastUpdateDate_T;
之后我得到这个例如:
ID Value LastUpdateDate ID_T LastUpdateDate_T
1 4 2017-01-01 1 2017-01-01
2 4 2017-01-03 2 2017-01-03
3 4 2017-01-03 3 2017-01-03
我删除了最后两列,因为它们是重复的,以获得我需要的内容。同样,这可行,但我想知道这是否是最好的方法?
我正在使用 Azure SQL DB。
【问题讨论】:
【参考方案1】:你的方法很好。我会使用窗口函数:
SELECT *
INTO @CurrentOverviewTableName
FROM (SELECT ht.*,
MAX(LastUpdateDate) OVER (PARTITION BY id) AS max_LastUpdateDate
FROM @HistoryTableName ht
) ht
WHERE max_LastUpdateDate = LastUpdateDate;
如果您不想删除该列,请列出您想要的列,而不是使用SELECT *
。如果您也不想这样做,请将条件移至 WHERE
子句:
SELECT ht.*
INTO @CurrentOverviewTableName
FROM @HistoryTableName ht
WHERE ht.LastUpdateDate = (SELECT MAX(h2.LastUpdateDate)
FROM @CurrentOverviewTableName ht2
WHERE ht2.id = ht.id
);
【讨论】:
【参考方案2】:假设他们不返回 Value,您可以使用下面的代码。如果您希望它们在值中回归的选项,那么您需要一个标识列,最好作为表的主键,并且您将取而代之的是最大标识。子查询会略有变化。主键还可以使子查询更容易返回,只使用主键而不是两个值,ID 和值。见下文。
--change the date for a different time period
DECLARE @updateDate date = '2017-01-12'
DECLARE @temp TABLE (ID int, Value int, updateDate date)
INSERT INTO @temp VALUES
(1, 4, '2017-01-01')
,(2, 4, '2017-01-03')
,(3, 4, '2017-01-03')
,(1, 7, '2017-01-04')
,(2, 5, '2017-01-08')
,(3, 5, '2017-01-10')
,(2, 8, '2017-01-11')
SELECT dT.*
,(SELECT T2.updateDate
FROM @temp T2
WHERE T2.ID = dT.Id AND T2.Value = dT.MaxValue) [LastUpdateDate]
FROM (
SELECT ID, MAX(Value) MaxValue
FROM @temp T
WHERE T.updateDate <= @updateDate
GROUP By ID
) AS dT
【讨论】:
以上是关于SQL:如何最好地查询历史表以创建特定日期的快照概览的主要内容,如果未能解决你的问题,请参考以下文章
Oracle:有效地使用where子句过滤时间戳列以获取特定日期的所有记录
如何有效地查询多个表以在 dataGrid 中生成 excel STYLE 报告