Sql 如何获取两列组合的最后记录?

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

我有一种情况,我认为可以与Camelm、Keepa等服务相比。 假设我每天跟踪几个国家的一篇文章的价格。所以我的表,我们称之为趋势,看起来像这样

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。具有正确索引的相关子查询通常具有最佳性能或接近最佳性能。