SQL 查询:多项挑战

SQL query : multiple challenges

不是 SQL 专家,我正在努力解决以下问题:

我继承了一个较大的 table(大约 1 亿行),其中包含带有时间戳的事件,这些事件代表了大多数短暂现象的阶段转变。不幸的是,事件的记录方式有些奇怪,table 如下所示:

phen_ID   record_time  producer_id   consumer_id  state   ...

000123    10198789                               start
          10298776     000123        000112      hjhkk
000124    10477886                               start
          10577876     000124        000123      iuiii
000124    10876555                               end

每个现象 (phen-ID) 都有一个开始事件和理论上的结束事件,尽管它可能还没有发生因此没有被记录下来。每个现象都可以经历几个状态。不幸的是,对于某些州,ID 记录在产品或消费者字段中。另外,状态的数量不固定,状态之间的时间也不固定。

首先,我需要创建一个 SQL 语句,为每个 phen-ID 显示开始时间和最后记录事件的时间(可以是结束状态或中间状态之一).

仅考虑一个 phen-ID,我设法将以下 SQL 组合在一起:

WITH myconstants (var1) as (
   values ('000123')
)

select min(l.record_time), max(l.record_time) from 
   (select distinct *  from public.phen_table JOIN myconstants ON var1 IN (phen_id, producer_id, consumer_id)
 ) as l

由于开始状态总是具有特定现象的最短记录时间,因此上述陈述正确地returns记录时间范围为一行,而不管结束状态是什么。

显然我必须手动提供 phen-ID。

我怎样才能使这项工作得到一行开始时间和每个唯一 phen-ID 的最大记录时间?试着适应 select distinct phen-id ... 之类的东西,但无法将它们自动“喂”到上面。或者我在这里完全偏离了目标?

补充: 澄清一下,使用上面的 table 的理想输出应该是这样的:

ID         min-time      max-time
000123     10198789      10577876   (min-time is start, max-time is state iuii)
000124     10477886      10876555   (min-time is start, max-time is end state)

我认为您的方向是正确的。试试这个,看看它是否是您要找的:

select
    min(l.record_time)
    ,max(l.record_time)
    ,coalesce(phen_id, producer_id, consumer_id) as [Phen ID]
from public.phen_table
group by coalesce(phen_id, producer_id, consumer_id)

union all 可能是一个选项:

select phen_id, 
    min(record_time) as min_record_time, 
    max(record_time) as max_record_time
from (
    select phen_id, record_time from phen_table
    union all select producer_id, record_time from phen_table
    union all select consumer_id, record_time from phen_table
) t
where phen_id is not null
group by phen_id

另一方面,如果你想要优先级,那么你可以使用coalesce():

select coalesce(phen_id, producer_id, consumer_id) as phen_id, 
    min(record_time) as min_record_time, 
    max(record_time) as max_record_time
from phen_table
group by coalesce(phen_id, producer_id, consumer_id)

这两个查询的逻辑并不完全相同。如果三列中有不止一列不是 null,并且值不同,则第一个查询会考虑所有非 null 值,而第二个查询仅考虑“第一个”非 null 值。


编辑

在您最终标记的 Postgres 中,union all 解决方案可以通过横向连接更有效地表达:

select x.phen_id, 
    min(p.record_time) as min_record_time, 
    max(p.record_time) as max_record_time
from phen_table p
cross join lateral (values (phen_id), (producer_id), (consumer_id)) as x(phen_id)
where x.phen_id is not null
group by x.phen_id