Как узнать цену на конкретную дату для использования в графиках?

Как правильно создать запрос в PostgreSQL, чтобы на каждую дату для каждого артикула отобразить последнюю изменённую цену и цену клиента? У меня есть три таблицы: первая содержит список артикулов, а вторая и третья - изменения цен с указанием даты, артикула и цены. Я пробовал использовать DAX запросы и Power Query для создания кросс-таблицы, но теперь хочу сделать это с помощью SQL. В результате запроса мне нужна таблица, где будет указана последняя цена и цена клиента для каждой даты и артикула. Мой текущий запрос выглядит следующим образом: 
<pre><code class="sql">with ds as (
SELECT generate_series(
	'2023-01-01',
	'2025-12-31',
	'1 day'::interval
	)::date AS date
),
items as (
	SELECT distinct article FROM ozon.items
	UNION
	SELECT distinct article FROM wildberries.items
	UNION
	SELECT distinct article FROM yandex.items
	UNION
	SELECT distinct article FROM sber.items
),
all_combinations AS (
    SELECT ds.date, items.article
    FROM ds
    CROSS JOIN items
),
ozon_client_prices as (
	SELECT 
		date(updated_at) as date,
		article,
		value as client_price
	FROM ozon._history_of_client_prices
),
ozon_self_prices as (
	SELECT 
		date(update_at) as date,
		article,
		value as self_price
	FROM ozon._history_of_self_prices
),
combined_prices AS (
    SELECT 
        all_combinations.date,
        all_combinations.article,
        ocp.client_price,
        osp.self_price,
        MAX(ocp.client_price) OVER (
			PARTITION BY all_combinations.article ORDER 
  • 27 сентября 2024 г. 13:43
Ответы на вопрос 2
Хорошо, давайте доработаем ваш SQL-запрос, чтобы получить последнюю изменённую цену и цену клиента для каждой даты и артикулов. Для этого необходимо использовать подзапросы, которые будут находить самые последние изменения цен для данных дат. 

Ваш запрос уже содержит постепенно включающие элементы для получения нужной информации, и нужно добавить логику выбора последней цены на каждую дату. Вот переработанный запрос:

```sql
WITH ds AS (
    SELECT generate_series(
        '2023-01-01'::date,
        '2025-12-31'::date,
        '1 day'::interval
    )::date AS date
),
items AS (
    SELECT DISTINCT article FROM ozon.items
    UNION
    SELECT DISTINCT article FROM wildberries.items
    UNION
    SELECT DISTINCT article FROM yandex.items
    UNION
    SELECT DISTINCT article FROM sber.items
),
all_combinations AS (
    SELECT ds.date, items.article
    FROM ds
    CROSS JOIN items
),
ozon_client_prices AS (
    SELECT 
        date(updated_at) AS date,
        article,
        value AS client_price
    FROM ozon._history_of_client_prices
),
ozon_self_prices AS (
    SELECT 
        date(updated_at) AS date,
        article,
        value AS self_price
    FROM ozon._history_of_self_prices
),
latest_client_prices AS (
    SELECT 
        ac.date,
        ac.article,
        ocp.client_price,
        ROW_NUMBER() OVER (PARTITION BY ac.article ORDER BY ocp.date DESC) AS rn
    FROM all_combinations ac
    LEFT JOIN ozon_client_prices ocp ON ac.date >= ocp.date 
),
latest_self_prices AS (
    SELECT 
        ac.date,
        ac.article,
        osp.self_price,
        ROW_NUMBER() OVER (PARTITION BY ac.article ORDER BY osp.date DESC) AS rn
    FROM all_combinations ac
    LEFT JOIN ozon_self_prices osp ON ac.date >= osp.date 
)
SELECT 
    ac.date,
    ac.article,
    coalesce(lcp.client_price, 0) AS client_price,
    coalesce(lsp.self_price, 0) AS self_price
FROM all_combinations ac
LEFT JOIN latest_client_prices lcp ON ac.date = lcp.date AND ac.article = lcp.article AND lcp.rn = 1
LEFT JOIN latest_self_prices lsp ON ac.date = lsp.date AND ac.article = lsp.article AND lsp.rn = 1
ORDER BY ac.date, ac.article;
```

### Объяснение запроса:

1. **Образование дат**: `ds` - образует серию дат от `'2023-01-01'` до `'2025-12-31'`.

2. **Артикулы**: `items` - объединяет все уникальные артики из разных таблиц.

3. **Все комбинации**: `all_combinations` - создается кросс-продукт всех дат и артикулов.

4. **Цены клиентов и собственные цены**: `ozon_client_prices` и `ozon_self_prices` - выбирают данные цен с их обновлениями.

5. **Последние цены**: `latest_client_prices` и `latest_self_prices` - используют `ROW_NUMBER()` для выбора последней цены до (или на) каждой из дат.

6. **Финальный выбор**: На выходе мы выбираем дату, артикул, и цены, используя `LEFT JOIN` для связки каждой даты и артикула с их последними ценами.

Таким образом, вы получите таблицу с последней ценой для каждого артикула на каждую дату.

Обратите внимание, что если у вас могут отсутствовать цены на определённые даты, результат для этих дат будет иметь `NULL` значения, которые мы заменяем на 0 с помощью функции `coalesce`. 

Этот запрос будет работать для PostgreSQL. Если будете его тестировать, убедитесь, что типы данных, такие как `updated_at` и другие, соответствуют вашим данным.
Нужен вложенный подзапрос, который выведет артикул продукта и максимальное время за дату. 
Что-то вроде такого
SELECT   
    DATE(datetime) AS date,  
    article,  
    price  
FROM   
    client_prices_history  
WHERE   
    (article, datetime) IN (  
        SELECT   
            article,   
            MAX(datetime) AS max_datetime  
        FROM   
            client_prices_history  
        GROUP BY   
            article, DATE(datetime)  
    );
Похожие вопросы