使用 SQL 高效查询记录的最新版本
Efficiently query for the latest version of a record using SQL
我需要查询 table 以获取所有可用日期(日终时间序列)的记录的最新版本。下面的示例说明了我正在努力实现的目标。
我的问题是 table 的设计(主键等)和 LEFT OUTER JOIN
查询是否以最有效的方式实现了这个目标。
CREATE TABLE [PriceHistory]
(
[RowID] [int] IDENTITY(1,1) NOT NULL,
[ItemIdentifier] [varchar](10) NOT NULL,
[EffectiveDate] [date] NOT NULL,
[Price] [decimal](12, 2) NOT NULL,
CONSTRAINT [PK_PriceHistory]
PRIMARY KEY CLUSTERED ([ItemIdentifier] ASC, [RowID] DESC, [EffectiveDate] ASC)
)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-15',5.50)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-16',5.75)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-16',6.25)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-17',6.05)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-18',6.85)
GO
SELECT
L.EffectiveDate, L.Price
FROM
[PriceHistory] L
LEFT OUTER JOIN
[PriceHistory] R ON L.ItemIdentifier = R.ItemIdentifier
AND L.EffectiveDate = R.EffectiveDate
AND L.RowID < R.RowID
WHERE
L.ItemIdentifier = 'ABC' and R.EffectiveDate is NULL
ORDER BY
L.EffectiveDate
跟进:Table 可以包含数千个 ItemIdentifiers,每个 ItemIdentifiers 都有数十年的价格数据。出于审计原因,需要保留数据的历史版本。假设我查询 table 并在报告中使用数据。我在生成报告时存储 @MRID = Max(RowID)
。现在,如果“2016-03-16”上 'ABC' 的价格在稍后的某个日期得到更正,我可以使用 @MRID 修改查询并复制我之前 运行 的报告。
我假设您的 table 中有超过 1 个 ItemIdentifier。您的设计有点问题,因为您在 table 中保留了数据的版本。但是,您可以很容易地执行类似的操作,以便为每个 ItemIdentifier 获取最新的。
with sortedResults as
(
select *
, ROW_NUMBER() over(PARTITION by ItemIdentifier order by EffectiveDate desc) as RowNum
from PriceHistory
)
select *
from sortedResults
where RowNum = 1
简答,不。
您正在点击相同的 table 两次,并且可能会创建循环 table 扫描,具体取决于您现有的索引。在最好的情况下,您会导致循环索引查找,然后丢弃大部分行。
这将是针对您所问内容的最有效查询。
SELECT
L.EffectiveDate,
L.Price
FROM
(
SELECT
L.EffectiveDate,
L.Price,
ROW_NUMBER() OVER (
PARTITION BY
L.ItemIdentifier,
L.EffectiveDate
ORDER BY RowID DESC ) RowNum
FROM [PriceHistory] L
WHERE L.ItemIdentifier = 'ABC'
) L
WHERE
L.RowNum = 1;
@SeanLange 的答案稍作修改后,将为您提供每个日期的最后一行,而不是每个产品:
with sortedResults as
(
select *
, ROW_NUMBER() over(PARTITION by ItemIdentifier, EffectiveDate
ORDER by ID desc) as RowNum
from PriceHistory
)
select ItemIdentifier, EffectiveDate, Price
from sortedResults
where RowNum = 1
order by 2
我需要查询 table 以获取所有可用日期(日终时间序列)的记录的最新版本。下面的示例说明了我正在努力实现的目标。
我的问题是 table 的设计(主键等)和 LEFT OUTER JOIN
查询是否以最有效的方式实现了这个目标。
CREATE TABLE [PriceHistory]
(
[RowID] [int] IDENTITY(1,1) NOT NULL,
[ItemIdentifier] [varchar](10) NOT NULL,
[EffectiveDate] [date] NOT NULL,
[Price] [decimal](12, 2) NOT NULL,
CONSTRAINT [PK_PriceHistory]
PRIMARY KEY CLUSTERED ([ItemIdentifier] ASC, [RowID] DESC, [EffectiveDate] ASC)
)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-15',5.50)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-16',5.75)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-16',6.25)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-17',6.05)
INSERT INTO [PriceHistory] VALUES ('ABC','2016-03-18',6.85)
GO
SELECT
L.EffectiveDate, L.Price
FROM
[PriceHistory] L
LEFT OUTER JOIN
[PriceHistory] R ON L.ItemIdentifier = R.ItemIdentifier
AND L.EffectiveDate = R.EffectiveDate
AND L.RowID < R.RowID
WHERE
L.ItemIdentifier = 'ABC' and R.EffectiveDate is NULL
ORDER BY
L.EffectiveDate
跟进:Table 可以包含数千个 ItemIdentifiers,每个 ItemIdentifiers 都有数十年的价格数据。出于审计原因,需要保留数据的历史版本。假设我查询 table 并在报告中使用数据。我在生成报告时存储 @MRID = Max(RowID)
。现在,如果“2016-03-16”上 'ABC' 的价格在稍后的某个日期得到更正,我可以使用 @MRID 修改查询并复制我之前 运行 的报告。
我假设您的 table 中有超过 1 个 ItemIdentifier。您的设计有点问题,因为您在 table 中保留了数据的版本。但是,您可以很容易地执行类似的操作,以便为每个 ItemIdentifier 获取最新的。
with sortedResults as
(
select *
, ROW_NUMBER() over(PARTITION by ItemIdentifier order by EffectiveDate desc) as RowNum
from PriceHistory
)
select *
from sortedResults
where RowNum = 1
简答,不。
您正在点击相同的 table 两次,并且可能会创建循环 table 扫描,具体取决于您现有的索引。在最好的情况下,您会导致循环索引查找,然后丢弃大部分行。
这将是针对您所问内容的最有效查询。
SELECT
L.EffectiveDate,
L.Price
FROM
(
SELECT
L.EffectiveDate,
L.Price,
ROW_NUMBER() OVER (
PARTITION BY
L.ItemIdentifier,
L.EffectiveDate
ORDER BY RowID DESC ) RowNum
FROM [PriceHistory] L
WHERE L.ItemIdentifier = 'ABC'
) L
WHERE
L.RowNum = 1;
@SeanLange 的答案稍作修改后,将为您提供每个日期的最后一行,而不是每个产品:
with sortedResults as
(
select *
, ROW_NUMBER() over(PARTITION by ItemIdentifier, EffectiveDate
ORDER by ID desc) as RowNum
from PriceHistory
)
select ItemIdentifier, EffectiveDate, Price
from sortedResults
where RowNum = 1
order by 2