如何基于PostgreSQL中其他列的某些条件过滤最后一行

bxjv4tth  于 2023-01-08  发布在  PostgreSQL
关注(0)|答案(2)|浏览(135)

假设我有一个表(DeliveryEvent),它是这样的,按delivery_id分组,其中event_type 2是一个"scheduled"事件,3是一个"unscheduled"事件,4是一个"completed"事件:
| 身份证|创建|事件类型|交货标识|额外的|
| - ------| - ------| - ------| - ------| - ------|
| 1个|2022年10月27日18时04分|第二章|小行星10005||
| 第二章|2022年10月27日19时|三个|小行星10005| {"无法交付"}|
| 三个|2022年10月27日19时20分|第二章|小行星10005||
| 四个|2022年10月27日20时30分|三个|小行星10005| {"超时"}|
| 五个|2022年10月27日21时15分|第二章|小行星10005||
| 六个|2022年10月27日22时40分|三个|小行星10005| {"超时"}|
| 七|2022年10月27日22时55分|第二章|小行星10005||
| 八个|2022年10月27日23时|四个|小行星10005||
...
我需要一个结果表,对于每一个由于"超时",我有关于发生在此超时之前的预定事件的信息,以获得预定和非预定之间的持续时间。
从下面的SELECT中,我获得了计划事件与其他计划外事件的不同组合(超时):

SELECT
    scheduled.id as scheduled_id, 
    scheduled.created as scheduled_time, 
    scheduled.event as scheduled_event, 
    scheduled.delivery_id as delivery_id,
    unscheduled.id as unscheduled_id, 
    unscheduled.created as unscheduled_time, 
    unscheduled.event as unscheduled_event, 
    unscheduled.extra as extra
FROM
    delivery_event scheduled_event
JOIN
    delivery_event unscheduled_event ON scheduled.delivery_id = 10005 
    AND unscheduled.delivery_id = 10005 
    AND unscheduled.event = 3 
    AND scheduled.event = 2 
    AND scheduled.created < unscheduled.created
    AND unscheduled.extra->>'timeout'

| 计划标识|预定时间|预定事件|交货标识|未计划_id|计划外时间|预定事件|额外的|
| - ------| - ------| - ------| - ------| - ------| - ------| - ------| - ------|
| 五个|2022年10月27日21时15分|第二章|小行星10005|六个|2022年10月27日22时40分|三个|{"超时"}|
| 三个|2022年10月27日19时20分|第二章|小行星10005|六个|2022年10月27日22时40分|三个|{"超时"}|
| 1个|2022年10月27日18时04分|第二章|小行星10005|六个|2022年10月27日22时40分|三个|{"超时"}|
| 三个|2022年10月27日19时20分|第二章|小行星10005|四个|2022年10月27日20时30分|三个|{"超时"}|
| 1个|2022年10月27日18时04分|第二章|小行星10005|四个|2022年10月27日20时30分|三个|{"超时"}|
但我只想得到下面的结果
| 计划标识|预定时间|预定事件|交货标识|未计划_id|计划外时间|预定事件|额外的|
| - ------| - ------| - ------| - ------| - ------| - ------| - ------| - ------|
| 五个|2022年10月27日21时15分|第二章|小行星10005|六个|2022年10月27日22时40分|三个|{"超时"}|
| 三个|2022年10月27日19时20分|第二章|小行星10005|四个|2022年10月27日20时30分|三个|{"超时"}|
仅限于恰好在未调度事件之前发生的调度事件,即,由于超时而在每个未调度事件之前的最后调度事件。

jtoj6r0c

jtoj6r0c1#

试试这个:

SELECT a.*
FROM (
SELECT delivery_id
     , lag(id, 1) OVER w AS scheduled_id
     , lag(created, 1) OVER w AS scheduled_time
     , lag(event , 1) OVER w AS scheduled_event
     , id AS unscheduled_id
     , created AS unscheduled_time
     , event AS unscheduled_event
     , extra
  FROM delivery_event
 WHERE delivery_id = 10005
WINDOW w AS (PARTITION BY delivery_id ORDER BY created ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
) AS a
WHERE a.scheduled_event = 2
  AND a.unscheduled_event = 3
  AND a.extra = '{"timeout"}' :: json
z9smfwbn

z9smfwbn2#

我能想到两种解决方案。最简单的可能是使用distinct on子句来删除所有具有重复unscheduled_id的行,并在scheduled.created上使用order by子句来确保返回正确的行。

SELECT DISTINCT ON (unscheduled.id)
    scheduled.id as scheduled_id, 
    scheduled.created as scheduled_time, 
    scheduled.event as scheduled_event, 
    scheduled.delivery_id as delivery_id,
    unscheduled.id as unscheduled_id, 
    unscheduled.created as unscheduled_time, 
    unscheduled.event as unscheduled_event, 
    unscheduled.extra as extra
FROM
    delivery_event scheduled_event
JOIN
    delivery_event unscheduled_event ON scheduled.delivery_id = 10005 
    AND unscheduled.delivery_id = 10005 
    AND unscheduled.event = 3 
    AND scheduled.event = 2 
    AND scheduled.created < unscheduled.created
    AND unscheduled.extra->>'timeout'
ORDER BY scheduled.created DESC

另一种解决方案是使用左侧连接,以便只连接最近安排的事件。

SELECT
    scheduled.id as scheduled_id, 
    scheduled.created as scheduled_time, 
    scheduled.event as scheduled_event, 
    scheduled.delivery_id as delivery_id,
    unscheduled.id as unscheduled_id, 
    unscheduled.created as unscheduled_time, 
    unscheduled.event as unscheduled_event, 
    unscheduled.extra as extra
FROM
    delivery_event unscheduled_event
JOIN
    LEFT JOIN LATERAL (
        SELECT scheduled.id, 
        scheduled.created, 
        scheduled.event, 
        scheduled.delivery_id
        FROM delivery_event scheduled
        WHERE scheduled.delivery_id = 10005 
        AND scheduled.event = 2 
        AND scheduled.created < unscheduled.created
        ORDER BY scheduled.created DESC 
    LIMIT 1) scheduled ON TRUE 
WHERE unscheduled.delivery_id = 10005 
    AND unscheduled.event = 3 
    AND unscheduled.extra->>'timeout'

对于这样的连接表,需要注意一点:尽管只使用一个相关行进行连接非常方便,但它往往会带来严重的性能缺陷,因此请务必检查这两种方法中的任何一种方法的性能是否满足您的特定环境。

相关问题