найти новую_ценку для последней даты изменения каждого идентификатора продукта - PullRequest
1 голос
/ 26 февраля 2020

Вот таблица:

create table products (
product_id int,
new_price int,
change_date date,
primary key (product_id, change_date));

insert into products values
(1, 20, '2019-08-14'),
(2, 50, '2019-08-14'),
(1, 30, '2019-08-15'),
(1, 35, '2019-08-16'),
(2, 65, '2019-08-17'),
(3, 20, '2019-08-18');

вопрос: найдите new_price для последней даты изменения каждого product_id. Вот мое решение:

select a.product_id, a.new_price, b.change_date from products a join 
(select product_id, max(change_date) change_date from products 
 group by product_id) b
 on a.product_id = b.product_id and a.change_date = b.change_date;

оно работает как положено:

product_id | new_price | change_date
  1             35        2019-08-16
  2             65        2019-08-17
  3             20        2019-08-18

Есть ли более эффективный способ решить эту проблему? это выглядит для меня простым вопросом, но я должен использовать подзапрос, чтобы решить его, поэтому я ищу лучшее решение. Я использую PostgreSQL. Спасибо

Ответы [ 2 ]

1 голос
/ 26 февраля 2020

Один из способов сделать это - использовать DISTINCT ON (postgresql Speci c особенность) и LAST_VALUE оконную функцию:

SELECT DISTINCT ON (product_id)
       product_id,
       LAST_VALUE(new_price) OVER all_rows_by_product_id,
       LAST_VALUE(change_date) OVER all_rows_by_product_id
FROM products
-- named window, you could also simply repeat its definition in both rows above
WINDOW all_rows_by_product_id AS (PARTITION BY product_id ORDER BY change_date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
;
┌────────────┬────────────┬────────────┐
│ product_id │ last_value │ last_value │
├────────────┼────────────┼────────────┤
│          1 │         35 │ 2019-08-16 │
│          2 │         65 │ 2019-08-17 │
│          3 │         20 │ 2019-08-18 │
└────────────┴────────────┴────────────┘
(3 rows)

Примечание: в этом случае SELECT DISTINCT также будет работать, так как все строки для product_id будут идентичны. Это сделало бы этот запрос не postgresql -specifi c.
Однако DISTINCT ON (product_id) ближе к тому, что вы хотите express, плюс он все равно вернет то, что вы хотите, даже если вы добавите какой-то другой столбец.

0 голосов
/ 26 февраля 2020

Это один из основных способов решения подобной проблемы, хотя он сопровождается предупреждением о том, что если в один день появятся две новые цены, он вернет оба значения

Альтернативой является использование номера строки:

select x.product_id, x.new_price, x.change_date from
(
  select p.product_id, p.new_price, p.change_date, row_number() over(partition by p.product_id order by p.change_date desc) rn
  from products p
) x
where x.rn=1

Аналитические c функции немного похожи на встроенную операцию группировки - набор результатов разбивается (группируется) по идентификатору продукта, а строки нумеруются в порядке убывания даты. У каждого раздела есть строка № 1, которая является самой последней датой. Предложение external where выбирает только те строки с rn = 1, которые являются самыми последними строками

. Это вернет только одну цену, если в день их две, но неизвестно, какую из них вы получите. Чтобы убедиться, добавьте еще одно правило к заказу, например, добавление в цену (всегда дает более высокую цену) или другой столбец. Вы также можете увеличить гранулярность даты, включив в нее также время

С точки зрения производительности, этот метод требует только одного сканирования данных таблицы, а не двух, хотя различные базы данных могут иметь определенные c оптимизации для часто используется шаблон «получить последний ряд». Что было бы быстрее или дешевле, в вашем случае было бы что-то проверить

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...