Sql 如何获取两列组合的最后记录?
我有一种情况,我认为可以与Camelm、Keepa等服务相比。 假设我每天跟踪几个国家的一篇文章的价格。所以我的表,我们称之为趋势,看起来像这样Sql 如何获取两列组合的最后记录?,sql,sql-server,tsql,date,greatest-n-per-group,Sql,Sql Server,Tsql,Date,Greatest N Per Group,我有一种情况,我认为可以与Camelm、Keepa等服务相比。 假设我每天跟踪几个国家的一篇文章的价格。所以我的表,我们称之为趋势,看起来像这样 Id Created ArticleId Country Price ------------------------------------------------- 01 19/11/05 452 US 45.90 02 19/11/05 452
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
现在是第二天,我想更新趋势表。如果某个国家的价格仍然相同,我将跳过文章/国家组合。如果有新的价格,我会增加一个新的记录
现在我想查询表以获得每个ArticleId
/Country
组合。但只有它的最后一条记录(按时间戳排序)。因此,以上面的示例为例,我希望获得ArticleId
<452
的04
、05
和06
记录。不是01
,02
和03
所以我从这个基本的查询开始。但我如何才能改变它以获得预期的结果呢
SELECT
*
FROM
Trend
ORDER BY
Created DESC
您可以通过组合使用
DISTINCT
和交叉应用来实现这一点
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
)会在另一个表上组成一个唯一键。如果这适用于您的数据库,您可以删除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
是一个主键
,并且已经被一个聚集索引所覆盖,如果是这样的话,上述方法应该适合大多数解决方案。一种方法使用相关子查询进行筛选:
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)
上建立索引
您可能还想考虑反<代码>左联接< /代码>方法:
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
最后,另一个典型的解决方案是使用聚合查询连接表:
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
哪个解决方案的性能更好取决于数据的大小和分布。谢谢。这似乎很管用。虽然这大约需要10万条记录的SELECT*FROM Trend
的5倍时间。你能想出另一种方法来获得同样的结果吗?@boop它总是需要比SELECT*
更长的时间,但鉴于数据集如此之小,它不应该花费太长的时间。你有覆盖指数吗?你能解释一下哪种解决方案在哪种情况下表现最好吗?一天大约有10万条记录。所以这个表将快速增长。@boop:很难事先判断,你应该根据你的数据测试每个解决方案。如果有大量的行和少量的组(文章/国家元组),则相关子查询可能提供良好的性能,但这只是猜测。@boop。具有正确索引的相关子查询通常具有最佳性能或接近最佳性能。