替换嵌套查询以获取最新的相关行

Replace nested query to get latest related row

提问人:ranidu harshana 提问时间:10/24/2023 最后编辑:Erwin Brandstetterranidu harshana 更新时间:10/24/2023 访问量:112

问:

我有一个查询来获取所有最新价格的罚款数据。在价格表中,有许多与产品相关的价格。要获得有效价格,我需要获取最新价格。这是查询。

SELECT *
FROM product 
LEFT JOIN product_price productPrice
          ON product.id = productPrice.product_id
          AND productPrice.valid_from =
               (SELECT valid_from FROM product_price
                WHERE product_price.is_active = true AND valid_from <= now()
                ORDER BY valid_from DESC LIMIT 1)
WHERE product.id = 1;

我的问题:有没有办法替换这里的嵌套查询,以便从product_price表中只获取一个最新日期,或者是否可以使用嵌套查询。

SQL PostgreSQL 每组 Greatest-n-Per-Group

评论

0赞 Frank Heikens 10/24/2023
你有问题吗?如果没有,则可以使用此构造。请检查 SQL 语句的结果。explain(analyze, verbose, buffers)
0赞 ranidu harshana 10/24/2023
使用嵌套查询是否会影响查询的性能
0赞 Frank Heikens 10/24/2023
每个 SQL 部分都会影响性能。有时它会提高性能,有时它会使事情变得更糟。这就是检查查询计划的原因。您有性能问题吗?
0赞 Stu 10/24/2023
是否可以使用嵌套查询 - 是的,SQL 是声明性的,您通常不关心如何,让优化器找出执行查询的最佳方式。如果您遇到性能问题,那就是另一个问题了。
0赞 ranidu harshana 10/24/2023
那么,在这种情况下,有没有其他方法可以做与你想象的相同的事情。还是这样更好?

答:

1赞 The Impaler 10/24/2023 #1

您可以使用来保留每个组的第一行。例如,您可以执行以下操作:DISTINCT ON

select distinct on (p.id) *
from product p
left join product_price pp on p.id = pp.product_id  
  and pp.valid_from <= now() and pp.is_active = true
where p.id = 1 
order by p.id, pp.valid_from desc
1赞 Erwin Brandstetter 10/24/2023 #2

要检索单个给定产品的数据,子查询通常是最快的。也是最灵活的。LATERAL

SELECT *
FROM   product p
LEFT   JOIN LATERAL (
   SELECT *
   FROM   product_price pp
   WHERE  pp.product_id = p.id
   AND    pp.is_active
   AND    pp.valid_from <= now()
   ORDER  BY pp.valid_from DESC
   LIMIT  1
   ) ON true
WHERE  p.id = 1;

看:

确保有一个索引,或一些改进的版本,这取决于未公开的细节。可以假设 PK 指数为 on。product_price (product_id, valid_from)product(id)

使用不同的查询样式,一次检索大多数或所有产品通常更快。但是您给定的查询清楚地表明了单个产品。

细微差别

您的原始行将返回所有相关行,其中包含最新的 .我的查询总是选择一个。通常,应定义以使其明确无误。product_pricevalid_from(product_id, valid_from)UNIQUE

您的原始版本也不会从存在任何相关行的地方返回任何行。Null 按降序排序在顶部排序,随后的联接条件将消除所有行。您将有一个约束,或者至少在查询中使用约束来最后对 null 值进行排序。看:product_pricevalid_from IS NULLvalid_from = nullNOT NULLDESC NULLS LAST

(你应该在问题中声明所有这些。