在Postgres中基于具有多个联接的时间戳和时间戳之间的依赖关系搜索数据

问题描述

我有两个表prod_replay_inprod_replay_out如下。

对于msg_type表中CDST010的prod_replay_in,在prod_replay_out表中确认为CDST01Cmsg_type与CDST100相同,它在prod_replay_out表中的确认消息为CDST10C。在下表中,cdsx_time很重要。例如,第二条CDST100消息将基于CDST10C具有第二条cdsx_time消息。

注意:2个表之间的联接基于cdsx_id,因为这在两个表之间是常见的。 CDST010和CDST01Ccdsx_idprod_replay_in表中分别只有相同的prod_replay_out一个条目。另外,CDST100和CDST10C消息的数量根据cdsx_id的不同而变化。

我要搜索什么?

我要按照以下条件在prod_replay_in表中搜索CDST100消息的数量

  • 如果CDST100的bancs_msg中的第四个字符与CDST01C的msg_body中的第四个字符相匹配,则获取一个CDST100。
  • 如果CDST100的bancs_msg中的第四个字符与第四个字符匹配,则获得第二个CDST100 第一个CDST10C的msg_body中的字符
  • 如果bancs_msg中CDST100的第四个字符与第四个字符匹配,则获取第三个CDST100 在msg_body中获得第二个CDST10C

以上模式类似于检查带有第一CDST10C的第二CDST100,检查带有第二CDST10C的第三CDST100,等等。

prod_replay_in

id(serial) | msg_type(varchar) | cdsx_time(timestamp)  | cdsx_id(varchar)    | bancs_msg(text)
------------------------------------------------------------------------------------------
8334698    | CDST010           | 2020-02-24 14:23:01.0 | T202005518525        | ABCD
8341809    | CDST100           | 2020-02-24 14:47:38.0 | T202005518525        | ANOC
8342732    | CDST100           | 2020-02-24 14:51:53.0 | T202005518525        | PHLM
8344890    | CDST100           | 2020-02-24 15:15:14.0 | T202005518525        | JKQO

prod_replay_out

    id(serial) | msg_type(varchar) | cdsx_time(timestamp)    | cdsx_id(varchar)     | msg_body(text)
    ------------------------------------------------------------------------------------------
    42164527   | CDST01C           | 2020-02-24 14:23:08.016 | T202005518525        | AQRS
    42176068   | CDST10C           | 2020-02-24 14:47:47.056 | T202005518525        | STUM
    42177522   | CDST10C           | 2020-02-24 14:52:00.031 | T202005518525        | XYZK
    42245814   | CDST10C           | 2020-02-24 15:30:00.045 | T202005518525        | ASQO

我尝试了什么?

我尝试创建用于匹配第一个CDST100和CDST01C的SQL查询,但不确定如何与带有CDST10C的后续CDST100进行比较?

SELECT count(T.id) FROM prod_replay_in T JOIN prod_replay_out O ON T.CDSX_ID = O.CDSX_ID
  JOIN prod_replay_out K ON K.CDSX_ID = O.CDSX_ID
  WHERE T.MSG_TYPE = 'CDST100'
  and O.msg_type = 'CDST01C'
  and K.msg_type = 'CDST10C'
  and ( (
        min(T.cdsx_time) > O.cdsx_time
        and substr(T.bancs_msg,4,1) = substr(O.msg_body,1)
        )
      );

解决方法

我尝试了以下代码。据我所知,它应该工作。请随时建议是否缺少任何情况。

Select count(T.*) from PROD_REPLAY_IN T,PROD_REPLAY_OUT O
Where T.msg_type = 'CDST100'
AND O.msg_type IN ('CDST01C','CDST10C')
AND T.cdsx_id = O.cdsx_id
AND substr(T.bancs_msg,4,1) = substr(O.msg_body,1)
AND (O.cdsx_id,O.cdsx_time) IN (Select Y.cdsx_id,Max(Y.cdsx_time) from PROD_REPLAY_OUT Y
        Where Y.msg_type IN ('CDST01C','CDST10C')
        AND O.cdsx_id = Y.cdsx_id
        AND T.cdsx_time > Y.cdsx_time
        GROUP BY Y.cdsx_id
        )
,

只要您知道按时间戳记,每prod_replay_out行将有一个对应的prod_replay_in行,您可以将其设置为使用窗口函数来回避开头的不同消息类型。重播:

with interleave as (
  select msg_type,cdsx_time,cdsx_id,bancs_msg as msg,'in' as direction
    from prod_replay_in
  union all
  select msg_type,msg_body as msg,'out' as direction
    from prod_replay_out
),match_cdst100 as (
  select cdsx_id,msg,lag(msg) over (partition by cdsx_id
                            order by cdsx_time) as last_msg
    from interleave
   where msg_type = 'CDST100'
)
select cdsx_id,count(*) 
  from match_cdst100
 where substr(msg,1) = substr(last_msg,1)
 group by cdsx_id;