SQL: выбрать строку с максимальным значением и сгруппировать по одному столбцу - PullRequest
2 голосов
/ 31 марта 2020

Первый раз задаю вопрос по stackoverflow, поэтому извиняюсь за любые ошибки.

Я пытаюсь преобразовать старую таблицу в новый формат.

Старая таблица / Пример ввода:

| id                               | collectionId                     | infoText   |
|----------------------------------|----------------------------------|------------|
| 20200227112631476162094432822589 | 20200227112630931296846572143651 | Step 0     |
| 20200227112631512664092998338570 | 20200227112630931296846572143651 | Step 1     |
| 20200227112631652576662844108316 | 20200227112630931296846572143651 | Successful |

Новая таблица / Вывод:

| collectionId                     | startTimestamp                  | stopTimeStamp                   | lastStatus |
|----------------------------------|---------------------------------|---------------------------------|-------------|
| 20200227112630931296846572143651 | 27-FEB-20 11.26.30.931000000 AM | 27-FEB-20 11.26.50.911000000 AM | Successful  |

По существу требуется следующее:

  • Создать строку из информации о последней строке из коллекции:
    • Строка с наибольшим идентификатором и идентичным идентификатором коллекции.
  • Преобразование первых 17 символов из идентификатора коллекции в метку времени начала
    (например: 2020022711263093 -> 27-FEB-20 11.26.30.931000000 AM).
  • Преобразовать первые 17 символов из последнего идентификатора из этой коллекции в метку времени остановки. (например: 2020022711263165 -> 27-FEB-20 11.26.50.911000000 AM).

Я пытался делать это весь день, и я чувствую, что я близок чтобы решить это. Однако, кажется, что все, что я пробую, приводит к другой ошибке.

Моя последняя попытка:

CREATE table newTable AS

SELECT
    a.collectionId                                                                AS collectionId,
    a.id                                                                          AS id,
    to_timestamp(substr(a.collectionId , 0, 17), 'YYYYMMDDHH24MISSFF')            AS starttimestamp,
    "STOPTIMESTAMP"                                                               AS stoptimestamp,
    a.infoText                                                                    AS lastStatus,
FROM
    oldTable a
    INNER JOIN (
        SELECT
            MAX(id),
            to_timestamp(substr(MAX(id), 0, 17), 'YYYYMMDDHH24MISSFF')            AS stoptimestamp,
            collectionId                                                          AS collectionId
        FROM
            oldTable
        GROUP BY
            collectionId
    ) b ON a.collectionId = b.collectionId
           AND stoptimestamp = b.stoptimestamp;

Это, однако, приводит к таблице с дублирующимися идентификаторами коллекции.

Я был бы очень признателен за помощь, поскольку я не настолько опытен с SQL. Показанный здесь пример изменен, чтобы быть более простым, таблица, с которой я работаю, имеет больше (дополнительный текст) полей и содержит более 2M + строк. Это Oracle XE 18 c DB, если это поможет.

Спасибо за помощь!

1 Ответ

1 голос
/ 31 марта 2020

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

select
    collection_id,
    to_timestamp(substr(collection_id, 1, 17), 'yyyymmddhh24missff') start_timestamp,
    to_timestamp(substr(id,            1, 17), 'yyyymmddhh24missff') end_timestamp,
    info_text last_status
from (
    select 
        t.*,
        row_number() over(partition by collection_id order by id desc) rn
    from mytable t
) t
where rn = 1

Демонстрация на DB Fiddle :

                   COLLECTION_ID | START_TIMESTAMP              | END_TIMESTAMP                | LAST_STATUS
-------------------------------: | :--------------------------- | :--------------------------- | :----------
20200227112630931296846572143651 | 27-FEB-20 11.26.30.931000000 | 27-FEB-20 11.26.31.652000000 | Successful 
...