Группировать по, отбрасывая старые данные в запросе - PullRequest
0 голосов
/ 04 июня 2018

У меня есть таблица (Oracle):

price
--------
integer id (pk)
integer part_id (fk)
number amount
timestamp change_timestamp

И всякий раз, когда цена за деталь изменяется, программное обеспечение (не мое) добавляет новую строку в эту таблицу.Вместо того, чтобы изменять данные и иметь одну запись на деталь, он добавляет новую строку в таблицу.Программное обеспечение ищет последнюю запись.Но «старые» данные остаются в таблице.

Я пытаюсь написать запрос, который дает мне а) текущую (последнюю) цену и б) дату, когда была введена цена.

Я написал этот запрос:

select part_id, amount, max(change_timestamp)
from price
group by part_id, amount

Но при этом возвращаются все записи для этой части, даже старые.

Как мне вернуть самую последнюю дату и сумму за эту дату при отбрасываниистарые, нерелевантные данные?

Нет, это не моя база данных, чтобы изменить или мое программное обеспечение, чтобы изменить.

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

Используйте ROW_NUMBER(), чтобы найти последнюю запись part_id.

SELECT part_id
    ,amount
    ,change_timestamp
FROM (
    SELECT price.*
        ,ROW_NUMBER() OVER (PARTITION BY part_id ORDER BY change_timestamp DESC) as rn
    FROM price  
    )   
WHERE rn = 1
0 голосов
/ 04 июня 2018

Но при этом возвращаются все записи для этой части, даже старые.

Это потому, что вы группируете по part_id, amount обеим, что учитывает несколько групп для каждой part_id, так как количество отличается для каждой записи.Чтобы получить только part_id и MAX(timestamp), достаточно просто удалить amount в group by и select.Если вы также хотите получить сумму, тогда

Вы можете использовать аналитическую функцию MAX и найти запись с этим change_timestamp

 SELECT part_id
    ,amount
    ,change_timestamp
FROM (
    SELECT p.*
        ,max(change_timestamp) OVER (PARTITION BY part_id) max_change_timestamp
    FROM price p
    )
WHERE change_timestamp = max_change_timestamp;

Или использовать row_number, который вы уже нашлив другом ответе.

Или используя коррелированный запрос:

SELECT part_id
    ,amount
    ,change_timestamp
FROM price  p1
WHERE change_timestamp = (
        SELECT MAX(change_timestamp)
         FROM price p2
        WHERE p2.part_id = p1.part_id
        );

или LAST (но не в последнюю очередь) агрегатная функция:

SELECT part_id
    ,MAX(amount) KEEP DENSE_RANK(LAST ORDER BY change_timestamp)
    ,MAX(change_timestamp)
GROUP BY part_id;
...