Функция ЗАДЕРЖКИ с функцией регистра / ранга

#sql #amazon-redshift

#sql #amazon-redshift

Вопрос:

У меня есть два сообщения (‘usb_port_reset’,’onewire_cable’) в столбце lbb_diag_value в одной таблице.

Я использую два столбца: created_at(с меткой времени), lbb_diag_value

Проблема: я хочу связать one_wire_cable для всех последовательных сообщений usb_port_reset, пока в таблице не будет найден другой one_wire_cable.

Например:

          Created_at    lbb_diag_value
         1 PM          onewire_cable
         1:15 PM       usb_port_reset
         3:00 Pm       usb_port_reset
         12Pm          onewire_cable
         Some Time     usb_port_reset
 

Текущее решение: я использую функцию задержки и соединение по левому краю, и это работает нормально, если у меня нет последовательных сообщений usb_port_reset.

Ниже приведен мой код:

   WITH CTE
AS (
    SELECT e2.identifier
        ,e2.created_at
        ,e2.model
        ,e2.sw_pkg_version
        ,e2.type
        ,e2.lbb_diag_value
        ,e2.lbb_diag_type
    FROM (
        SELECT e1.identifier
            ,e1.created_at
            ,e1.model
            ,e1.sw_pkg_version
            ,e1.lbb_diag_type
            ,e1.lbb_diag_value
            ,e1.type
        FROM eld_messages e1
        WHERE e1.type = 'lbb_diag'
            AND e1.lbb_diag_type = 'usb_port_reset'
            AND { % condition created_filter % } e1.created_at { % endcondition % }
        ) e2
    )
    ,onewire
AS (
    SELECT e2.identifier
        ,e2.lbb_diag_value
        ,e2.created_at
        ,e2.type
        ,e2.lbb_diag_type
        ,e2.prev_lbb_diag_type
        ,e2.prev_created_at
        ,e2.prev_lbb_diag_value
        ,e2.model
        ,e2.sw_pkg_version
        ,e2.seqnum
    FROM (
        SELECT e1.identifier
            ,e1.created_at
            ,e1.lbb_diag_value
            ,e1.type
            ,e1.lbb_diag_type
            ,e1.event_id
            ,e1.model
            ,e1.sw_pkg_version
            ,LAG(e1.lbb_diag_type) OVER (
                PARTITION BY e1.identifier ORDER BY e1.created_at
                    ,e1.event_id DESC
                ) AS prev_lbb_diag_type
            ,LAG(e1.created_at) OVER (
                PARTITION BY e1.identifier ORDER BY e1.created_at
                    ,e1.event_id DESC
                ) AS prev_created_at
            ,LAG(e1.lbb_diag_value) OVER (
                PARTITION BY e1.identifier ORDER BY e1.created_at
                    ,e1.event_id
                ) AS prev_lbb_diag_value
            ,row_number() OVER (
                PARTITION BY e1.lbb_diag_type ORDER BY e1.created_at
                    ,e1.event_id DESC
                ) seqnum
        FROM eld_messages e1
        WHERE e1.type = 'lbb_diag'
            AND e1.lbb_diag_type IN (
                'onewire_cable'
                ,'usb_port_reset'
                )
            AND { % condition created_filter % } e1.created_at { % endcondition % }
        ORDER BY e1.identifier
            ,e1.created_at
        ) e2
    WHERE (
            e2.lbb_diag_type = 'usb_port_reset'
            AND e2.prev_lbb_diag_type = 'onewire_cable'
            )
        OR (
            CASE 
                WHEN e2.lbb_diag_type = 'usb_port_reset'
                    AND e2.prev_lbb_diag_type = 'usb_port_reset'
                    THEN e2.seqnum = 1
                END
            )
    )
SELECT cte.identifier
    ,cte.created_at
    ,cte.model
    ,cte.sw_pkg_version
    ,cte.type
    ,cte.lbb_diag_type
    ,cte.lbb_diag_value
    ,onewire.prev_lbb_diag_value AS onewire_lbb_diag_value
    ,onewire.prev_created_at AS onewire_created_at
FROM cte
LEFT JOIN onewire ON cte.identifier = onewire.identifier
    AND cte.created_at = onewire.created_at; 
 

Ответ №1:

Будет ли работать вложить вложенный выбор с задержками и отфильтровать записи, в которых нет изменений в lbb_diag_value? Я не пытался понять весь контекст этого огромного запроса и нужны ли вам другие записи, но задержка может быть отличным способом определить границы, которые кажутся вам нужными.

 FROM (
    SELECT * FROM (
        SELECT e1.identifier ,e1.created_at ,e1.lbb_diag_value ,e1.type ,e1.lbb_diag_type ,e1.event_id
            ,e1.model ,e1.sw_pkg_version
            ,LAG(e1.lbb_diag_type) OVER (PARTITION BY e1.identifier ORDER BY e1.created_at ,e1.event_id DESC) AS prev_lbb_diag_type
            ,LAG(e1.created_at) OVER ( PARTITION BY e1.identifier ORDER BY e1.created_at ,e1.event_id DESC) AS prev_created_at
            ,LAG(e1.lbb_diag_value) OVER ( PARTITION BY e1.identifier ORDER BY e1.created_at ,e1.event_id) AS prev_lbb_diag_value
            ,row_number() OVER (PARTITION BY e1.lbb_diag_type ORDER BY e1.created_at ,e1.event_id DESC) seqnum
        FROM eld_messages e1
        WHERE e1.type = 'lbb_diag' AND e1.lbb_diag_type IN ('onewire_cable' ,'usb_port_reset')
            AND { % condition created_filter % } e1.created_at { % endcondition % }
        ORDER BY e1.identifier, e1.created_at
    ) t
    WHERE lbb_diag_value != prev_lbb_diag_value
) e2
 

Если вам нужны все записи, вы можете разбить их на два подвыбора с объединением (выбор, который вы оставили, соединен с выбором, который обнаруживает переходы), где переход (lbb_diag_value != prev_lbb_diag_value) заканчивается как новый столбец, указывающий записи, которые переходят от одного значения к другому.

Тогда идентификация ‘onewire_cable’ будет выглядеть примерно так:

 select * from (
...join...
) j where j.flip = 1 and j.lbb_diag_value = 'onewire_cable'