SQL: Select 具有最大值的行并按单列分组
SQL: Select row with max value and group by a single column
第一次在 Whosebug 上提问,如有错误请见谅。
我正在尝试将旧的 table 转换为新格式。
旧table / 输入示例:
| id | collectionId | infoText |
|----------------------------------|----------------------------------|------------|
| 20200227112631476162094432822589 | 20200227112630931296846572143651 | Step 0 |
| 20200227112631512664092998338570 | 20200227112630931296846572143651 | Step 1 |
| 20200227112631652576662844108316 | 20200227112630931296846572143651 | Successful |
新建table/输出:
| collectionId | startTimestamp | stopTimeStamp | lastStatus |
|----------------------------------|---------------------------------|---------------------------------|-------------|
| 20200227112630931296846572143651 | 27-FEB-20 11.26.30.931000000 AM | 27-FEB-20 11.26.50.911000000 AM | Successful |
基本上需要以下内容:
- 根据集合中最新行的信息创建一行:
- id最大且集合id相同的行。
- 将集合 id 的前 17 个字符转换为开始时间戳
(例如:2020022711263093 -> 27-FEB-20 11.26.30.931000000 AM)。
- 将该集合中最新 ID 的前 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;
然而,这会导致 table 具有重复的集合 ID。
非常感谢您的帮助,因为我在 SQL 方面经验不足。
此处显示的示例已修改为更简单,我正在使用的 table 具有更多(额外文本)字段并包含超过 200 万行。如果有帮助,它是一个 Oracle XE 18c 数据库。
感谢您的帮助!
您可以使用 window 函数来识别每组的最后一条记录,然后进行日期转换:
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
COLLECTION_ID | START_TIMESTAMP | END_TIMESTAMP | LAST_STATUS
-------------------------------: | :--------------------------- | :--------------------------- | :----------
20200227112630931296846572143651 | 27-FEB-20 11.26.30.931000000 | 27-FEB-20 11.26.31.652000000 | Successful
第一次在 Whosebug 上提问,如有错误请见谅。
我正在尝试将旧的 table 转换为新格式。
旧table / 输入示例:
| id | collectionId | infoText |
|----------------------------------|----------------------------------|------------|
| 20200227112631476162094432822589 | 20200227112630931296846572143651 | Step 0 |
| 20200227112631512664092998338570 | 20200227112630931296846572143651 | Step 1 |
| 20200227112631652576662844108316 | 20200227112630931296846572143651 | Successful |
新建table/输出:
| collectionId | startTimestamp | stopTimeStamp | lastStatus |
|----------------------------------|---------------------------------|---------------------------------|-------------|
| 20200227112630931296846572143651 | 27-FEB-20 11.26.30.931000000 AM | 27-FEB-20 11.26.50.911000000 AM | Successful |
基本上需要以下内容:
- 根据集合中最新行的信息创建一行:
- id最大且集合id相同的行。
- 将集合 id 的前 17 个字符转换为开始时间戳
(例如:2020022711263093 -> 27-FEB-20 11.26.30.931000000 AM)。 - 将该集合中最新 ID 的前 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;
然而,这会导致 table 具有重复的集合 ID。
非常感谢您的帮助,因为我在 SQL 方面经验不足。 此处显示的示例已修改为更简单,我正在使用的 table 具有更多(额外文本)字段并包含超过 200 万行。如果有帮助,它是一个 Oracle XE 18c 数据库。
感谢您的帮助!
您可以使用 window 函数来识别每组的最后一条记录,然后进行日期转换:
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
COLLECTION_ID | START_TIMESTAMP | END_TIMESTAMP | LAST_STATUS -------------------------------: | :--------------------------- | :--------------------------- | :---------- 20200227112630931296846572143651 | 27-FEB-20 11.26.30.931000000 | 27-FEB-20 11.26.31.652000000 | Successful