【问题标题】:How to get distinct values of a column by finding max timestamp for each and then get rest of the columns as well如何通过查找每个列的最大时间戳来获取列的不同值,然后也获取其余列
【发布时间】:2025-12-01 19:25:01
【问题描述】:

我有一个大的 oracle(Oracle 数据库 12c 企业版版本 12.1.0.2.0)表说 table_name 每 15 秒更新一次。 它有很多列,但我担心的是:

Name            Null?    Type                              
--------------- -------- --------------------------------- 
ID_1            NOT NULL NUMBER(38)                        
UTC_TIMESTAMP   NOT NULL TIMESTAMP(6) WITH TIME ZONE       
ID_2                     VARCHAR2(8)                       
SERVER_NAME              VARCHAR2(256)                     
ID_3                     NUMBER(38)                        
COUNT_1                  NUMBER(38)                        
COUNT_2                  NUMBER(38) 

我想做的是:

1) 获取 UTC_TIMESTAMP current_date - 5 分钟的所有记录(大约有 125K-150K)

2) 此数据将具有重复的 ID_1。因此,我只想获取每个 ID_1 在其重复项中具有 max(UTC_TIMESTAMP) 的那些记录。所以现在我们将拥有不同的 ID_1。

我尝试过的:使用以下 SQL

with temp_1 as (
select m.ID_2, m.ID_1, max(utc_timestamp) max_utc_timestamp
   from commsdesk.table_name m
   where m.ID_2 = 'TWC'
   group by m.ID_2, m.ID_1)
select f.utc_timestamp
  from commsdesk.table_name f
  join temp_1 t
    on t.max_utc_timestamp = f.utc_timestamp
   and t.ID_2 = f.ID_2
   and t.ID_1 = f.ID_1;

问题:我只能得到 ID_2、ID_1 和 UTC_TIMESTAMP,但我也想要所有其他列。 可以用 SQL 完成吗?

在 5 分钟的窗口中大约有 2200 条不同的 ID_1 和大约 125K-150K 记录。 因此,通过复制 excel 表中的 125K-150K 记录并过滤 2200 ID_1 中的每一个来找到每个 ID_1 的最大 UTC_TIMESTAMP 是不切实际的。 但如果有任何使用宏的快速方法,我也可以这样做。

样本虚拟数据:

ID_2    SERVER_NAME     ID_3    ID_1     UTC_TIMESTAMP               COUNT_1    COUNT_2
ABC     PQRS.ABC.TPO    2       303      24-JUL-17 03.41.55.000000000 PM +00:00 4   0
ABC     PQRS.ABC.TPO    2      1461      24-JUL-17 03.42.48.000000000 PM +00:00 1   7
ABC     PQRS.ABC.TPO    2         1      24-JUL-17 03.41.36.000000000 PM +00:00 2   3
ABC    PQRS.ABC.TPO     2      1461      24-JUL-17 03.41.16.000000000 PM +00:00 0   8
ABC    PQRS.ABC.TPO     1         1      24-JUL-17 03.41.11.000000000 PM +00:00 5   0
ABC    SRP.ROP.MTP      1         1      24-JUL-17 03.41.23.000000000 PM +00:00 0   0
ABC    SRP.ROP.MTP      2       303      24-JUL-17 03.41.34.000000000 PM +00:00 0   0
ABC    SRP.ROP.MTP      2      1461      24-JUL-17 03.41.31.000000000 PM +00:00 0   0
ABC    SRP.ROP.MTP      4       303      24-JUL-17 03.41.26.000000000 PM +00:00 4   8
ABC    SRP.ROP.MTP      2       303      24-JUL-17 03.41.20.000000000 PM +00:00 0   0
ABC    SRP.ROP.MTP      1      1461      24-JUL-17 03.41.01.000000000 PM +00:00 3   8
ABC    SRP.ROP.MTP      4         1      24-JUL-17 03.41.18.000000000 PM +00:00 9   1

预期输出:

ID_1    UTC_TIMESTAMP                           COUNT_1 COUNT_2
1       24-JUL-17 03.41.36.000000000 PM +00:00  2       3
303     24-JUL-17 03.41.55.000000000 PM +00:00  4       0
1461    24-JUL-17 03.42.48.000000000 PM +00:00  1       7

【问题讨论】:

  • 根据您解释的规则,您的示例数据没有任何重复项。请展示一些具有代表性的样本数据您对该数据的预期结果。
  • 我已经更新了示例数据并添加了预期的输出。抱歉延迟回复,但我在周末无法访问数据。在获得预期输出后,我会将其用作子查询以从预期输出中获取 MAX(UTC_TIMESTAMP) 和 SUM(COUNT_1) AND SUM(COUNT_2)。
  • 我第一次发布的查询得到了这个结果;我已经更新了我的答案以表明这一点。我不确定你对子查询的意思。您最终是在寻找 24-JUL-17 03.42.48, 7, 10` 的单一结果吗?
  • 是的,这正是我正在寻找的最终结果。我正在使用您的查询,并将在此处发布结果。再次感谢您。
  • 更新后的解决方案完全符合我的要求,但是当我尝试通过手动计算来验证输出时,数字不同。在我的示例中,当手动验证给出“199 2679”时,SQL 给出了“51 2434”。但是我无法共享用于此用例的全部数据。它也可能是数据中的东西。所以我将您的回复标记为答案。

标签: excel macros oracle12c


【解决方案1】:

您可以使用max() 聚合函数的the keep (dense_rank last ...) 版本(或者,如果您愿意,可以使用firstmin),类似于:

select id_1,
  max(utc_timestamp),
  max(id_2) keep (dense_rank last order by utc_timestamp) as id_2,
  max(server_name) keep (dense_rank last order by utc_timestamp) as server_name,
  max(id_3) keep (dense_rank last order by utc_timestamp) as id_3,
  max(count_1) keep (dense_rank last order by utc_timestamp) as count_1,
  max(count_2) keep (dense_rank last order by utc_timestamp) as count_2
from table_name
where utc_timestamp > current_timestamp - interval '5' minute
and utc_timestamp <= current_timestamp
group by id_1
order by id_1;

查询按id_1 分组,如果您想要最新的时间戳,max(utc_timestamp) 是“正常”。对于id_,其他列保留与具有该最大时间戳的行关联的值。

使用一些虚拟数据:

insert into table_name (id_1, utc_timestamp, id_2, server_name, id_3, count_1, count_2)
values (1, systimestamp at time zone 'UTC' - interval '30' second, 'TWC', 'test1', 301, 1, 1);
insert into table_name (id_1, utc_timestamp, id_2, server_name, id_3, count_1, count_2)
values (1, systimestamp at time zone 'UTC' - interval '60' second, 'TWC', 'test2', 302, 2, 2);
insert into table_name (id_1, utc_timestamp, id_2, server_name, id_3, count_1, count_2)
values (1, systimestamp at time zone 'UTC' - interval '90' second, 'TWC', 'test3', 303, 3, 3);
insert into table_name (id_1, utc_timestamp, id_2, server_name, id_3, count_1, count_2)
values (2, systimestamp at time zone 'UTC' - interval '45' second, 'TWC', 'test4', 304, 4, 4);
insert into table_name (id_1, utc_timestamp, id_2, server_name, id_3, count_1, count_2)
values (2, systimestamp at time zone 'UTC' - interval '15' second, 'TWC', 'test5', 305, 5, 5);

该查询得到结果:

      ID_1 MAX(UTC_TIMESTAMP)          ID_2     SERVE       ID_3    COUNT_1    COUNT_2
---------- --------------------------- -------- ----- ---------- ---------- ----------
         1 2017-07-21 18:38:22.944 UTC TWC      test1        301          1          1
         2 2017-07-21 18:38:38.399 UTC TWC      test5        305          5          5

您可以通过类似于您的尝试获得相同的结果:

with cte as (
  select id_1, max(utc_timestamp) max_utc_timestamp
  from table_name m
  where utc_timestamp > current_timestamp - interval '5' minute
  and utc_timestamp <= current_timestamp
  group by id_1
)
select t.id_1, t.utc_timestamp, t.id_2, t.server_name, t.id_3, t.count_1, t.count_2
from cte
join table_name t on t.id_1 = cte.id_1
and t.utc_timestamp = cte.max_utc_timestamp
order by t.id_1;

... 假设 id_1utc_timestamp 组合是唯一的(不确定您为什么使用 id_2 进行连接;也许这是唯一性所必需的?)。但这会降低效率,因为它必须查询真实表两次,一次是为了找到每个id_1 的最大时间戳,然后再次在连接中。可能值得运行这两个版本来比较结果和时间以及执行计划。


使用您的示例数据(于 2017 年 7 月 24 日更新),上面的第一个查询 - 修改为使用固定的时间戳范围进行匹配 - 获取:

     ID_1 MAX(UTC_TIMESTAMP)                ID_ SERVER_NAME        ID_3    COUNT_1    COUNT_2
---------- --------------------------------- --- ------------ ---------- ---------- ----------
         1 2017-07-24 15:41:36.000000 +00:00 ABC PQRS.ABC.TPO          2          2          3
       303 2017-07-24 15:41:55.000000 +00:00 ABC PQRS.ABC.TPO          2          4          0
      1461 2017-07-24 15:42:48.000000 +00:00 ABC PQRS.ABC.TPO          2          1          7

或删除您似乎不感兴趣的列:

select id_1,
  max(utc_timestamp),
  max(count_1) keep (dense_rank last order by utc_timestamp) as count_1,
  max(count_2) keep (dense_rank last order by utc_timestamp) as count_2
from table_name
where utc_timestamp > timestamp '2017-07-24 16:40:00 Europe/London' -- current_timestamp - interval '5' minute
and utc_timestamp <= timestamp '2017-07-24 16:45:00 Europe/London' -- current_timestamp
group by id_1
order by id_1;

      ID_1 MAX(UTC_TIMESTAMP)                   COUNT_1    COUNT_2
---------- --------------------------------- ---------- ----------
         1 2017-07-24 15:41:36.000000 +00:00          2          3
       303 2017-07-24 15:41:55.000000 +00:00          4          0
      1461 2017-07-24 15:42:48.000000 +00:00          1          7

然后你的下一步:

select max(max_utc_timestamp) as max_utc_timestamp,
  sum(count_1) as sum_count_1,
  sum(count_2) as sum_count_2
from (
  select max(utc_timestamp) as max_utc_timestamp,
    max(count_1) keep (dense_rank last order by utc_timestamp) as count_1,
    max(count_2) keep (dense_rank last order by utc_timestamp) as count_2
  from table_name
  where utc_timestamp > timestamp '2017-07-24 16:40:00 Europe/London' -- current_timestamp - interval '5' minute
  and utc_timestamp <= timestamp '2017-07-24 16:45:00 Europe/London' -- current_timestamp
  group by id_1
);

MAX_UTC_TIMESTAMP                 SUM_COUNT_1 SUM_COUNT_2
--------------------------------- ----------- -----------
2017-07-24 15:42:48.000000 +00:00           7          10

【讨论】:

  • 感谢您的回复亚历克斯。我应该在我的帖子中提到这一点。 ID_1、ID_2、ID_3 和 SERVER_NAME 的组合是唯一的。我正在尝试使用您的 SQL 版本,并将让您知道它是如何进行的。我也在做 sum(count_1) 和 sum(count_2)。我想这不会有太大区别,只是想提一下。
  • @300 - 那不就是简单的聚合吗?对于 id_1/id_2/id_3/server_name 的每个唯一组合,您想要最大时间戳和两个计数的总和?
  • 不,只有 count_1 和 count_2 是我想要求和的实际数字,但 id_1、id_2 和 id_3 是标识符。 ID_2 甚至是具有字母数字条目的 varchar。我会尝试发布一个虚拟的数据子集。
最近更新 更多