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
不是 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