如何获取 2 列组合的最后记录?
How to get the last records for a combination of 2 columns?
我认为我的情况可以与 CamelCamelCamel、Keepa 等服务进行比较。
假设我每天跟踪几个国家的一篇文章的价格。所以我的 table,我们称它为 Trend
,看起来像这样
Id Created ArticleId Country Price
-------------------------------------------------
01 19/11/05 452 US 45.90
02 19/11/05 452 CA 52.99
03 19/11/05 452 MX 99.99
04 19/11/06 452 US 20.00
05 19/11/06 452 CA 25.00
06 19/11/06 452 MX 50.00
...
97 19/11/05 738 US 12.99
98 19/11/05 738 CA 17.50
99 19/11/05 738 MX 45.50
所以是第二天,我想更新 Trend
table。如果某个国家/地区的价格仍然相同,我将跳过 article/country 组合。如果有新的价格我会添加新的记录。
现在我想查询 table 以获得每个 ArticleId
/ Country
组合。但只有它的最后一条记录(按时间戳排序)。因此,以上面的示例为例,我希望获得 ArticleId
452
的记录 04
、05
和 06
。不是 01
、02
和 03
所以我从这个基本查询开始。但是我如何才能改变它以获得我预期的结果呢?
SELECT
*
FROM
Trend
ORDER BY
Created DESC
您可以结合使用 DISTINCT
和 CROSS APPLY
。
SELECT DISTINCT ca.Id, ca.Created, t.ArticleId, t.Country, ca.Price
FROM Trend t
CROSS APPLY (SELECT TOP 1 Id, Created, Price
FROM Trend
WHERE ArticleId = t.ArticleId AND Country = t.Country
ORDER BY Created DESC) ca
通常在使用 APPLY
编写查询时,您的连接列(ArticleId
和 Country
)构成另一个 table 上的唯一键。如果这适用于您的数据库,您可以删除 DISTINCT
并加快查询速度。
SELECT ca.Id, ca.Created, a.ArticleId, a.Country, ca.Price
FROM Article a
CROSS APPLY (SELECT TOP 1 Id, Created, Price
FROM Trend
WHERE ArticleId = a.ArticleId AND Country = a.Country
ORDER BY Created DESC) ca
最后,如果您遇到性能问题,您可能需要创建一个索引。
CREATE NONCLUSTERED INDEX [NC_Trend_ArticleId] ON [Trend]
(
[ArticleId] ASC,
[Country] ASC,
[Created] ASC
)
INCLUDE ([Price])
据推测 Id
是一个 PRIMARY KEY
并且已经被一个 CLUSTERED INDEX
覆盖,如果是这样,以上应该适用于大多数解决方案。
一种方法使用相关子查询进行过滤:
select t.*
from trend t
where t.created = (
select max(t1.created)
from trend t1
where t1.articleId = t.articleId and t1.country = t.country
)
为了提高性能,您需要在 (articleId, country, created)
上建立索引。
您可能还想考虑反left join
方法:
select t.*
from trend t
left join trend t1
on t1.articleId = t.articleId
and t1.country = t.country
and t1.created > t.created
where t1.articleId is null
最后,另一种典型的解决方案是将 table 加入聚合查询:
select t.*
from trend t
inner join (
select articleId, country, max(created) created
from trend
group by articleId, country
) t1
on t1.articleId = t.articleId
and t1.country = t.country
and t1.created = t.created
哪种解决方案性能更好取决于数据的大小和分布。
我认为我的情况可以与 CamelCamelCamel、Keepa 等服务进行比较。
假设我每天跟踪几个国家的一篇文章的价格。所以我的 table,我们称它为 Trend
,看起来像这样
Id Created ArticleId Country Price
-------------------------------------------------
01 19/11/05 452 US 45.90
02 19/11/05 452 CA 52.99
03 19/11/05 452 MX 99.99
04 19/11/06 452 US 20.00
05 19/11/06 452 CA 25.00
06 19/11/06 452 MX 50.00
...
97 19/11/05 738 US 12.99
98 19/11/05 738 CA 17.50
99 19/11/05 738 MX 45.50
所以是第二天,我想更新 Trend
table。如果某个国家/地区的价格仍然相同,我将跳过 article/country 组合。如果有新的价格我会添加新的记录。
现在我想查询 table 以获得每个 ArticleId
/ Country
组合。但只有它的最后一条记录(按时间戳排序)。因此,以上面的示例为例,我希望获得 ArticleId
452
的记录 04
、05
和 06
。不是 01
、02
和 03
所以我从这个基本查询开始。但是我如何才能改变它以获得我预期的结果呢?
SELECT
*
FROM
Trend
ORDER BY
Created DESC
您可以结合使用 DISTINCT
和 CROSS APPLY
。
SELECT DISTINCT ca.Id, ca.Created, t.ArticleId, t.Country, ca.Price
FROM Trend t
CROSS APPLY (SELECT TOP 1 Id, Created, Price
FROM Trend
WHERE ArticleId = t.ArticleId AND Country = t.Country
ORDER BY Created DESC) ca
通常在使用 APPLY
编写查询时,您的连接列(ArticleId
和 Country
)构成另一个 table 上的唯一键。如果这适用于您的数据库,您可以删除 DISTINCT
并加快查询速度。
SELECT ca.Id, ca.Created, a.ArticleId, a.Country, ca.Price
FROM Article a
CROSS APPLY (SELECT TOP 1 Id, Created, Price
FROM Trend
WHERE ArticleId = a.ArticleId AND Country = a.Country
ORDER BY Created DESC) ca
最后,如果您遇到性能问题,您可能需要创建一个索引。
CREATE NONCLUSTERED INDEX [NC_Trend_ArticleId] ON [Trend]
(
[ArticleId] ASC,
[Country] ASC,
[Created] ASC
)
INCLUDE ([Price])
据推测 Id
是一个 PRIMARY KEY
并且已经被一个 CLUSTERED INDEX
覆盖,如果是这样,以上应该适用于大多数解决方案。
一种方法使用相关子查询进行过滤:
select t.*
from trend t
where t.created = (
select max(t1.created)
from trend t1
where t1.articleId = t.articleId and t1.country = t.country
)
为了提高性能,您需要在 (articleId, country, created)
上建立索引。
您可能还想考虑反left join
方法:
select t.*
from trend t
left join trend t1
on t1.articleId = t.articleId
and t1.country = t.country
and t1.created > t.created
where t1.articleId is null
最后,另一种典型的解决方案是将 table 加入聚合查询:
select t.*
from trend t
inner join (
select articleId, country, max(created) created
from trend
group by articleId, country
) t1
on t1.articleId = t.articleId
and t1.country = t.country
and t1.created = t.created
哪种解决方案性能更好取决于数据的大小和分布。