根据条件获取行

时间:2016-03-11 14:23:38

标签: sql postgresql amazon-redshift

我在Amazon Redshift上使用PostgreSQL。

我的表是:

drop table APP_Tax;
create temp table APP_Tax(APP_nm varchar(100),start timestamp,end1 timestamp);
insert into APP_Tax values('AFH','2018-01-26 00:39:51','2018-01-26 00:39:55'),
('AFH','2016-01-26 00:39:56','2016-01-26 00:40:01'),
('AFH','2016-01-26 00:40:05','2016-01-26 00:40:11'),
('AFH','2016-01-26 00:40:12','2016-01-26 00:40:15'), --row x
('AFH','2016-01-26 00:40:35','2016-01-26 00:41:34')  --row y

预期产出:

   'AFH','2016-01-26 00:39:51','2016-01-26 00:40:15'
   'AFH','2016-01-26 00:40:35','2016-01-26 00:41:34'

我必须在备用记录之间比较startendtime以及时间差异< 10秒获得下一条记录endtime,直至最后或最终记录。

I,e datediff(seconds,2018-01-26 00:39:55,2018-01-26 00:39:56) Is <10 seconds

我试过了:

SELECT a.app_nm
    ,min(a.start)
    ,max(b.end1)
FROM APP_Tax a
INNER JOIN APP_Tax b
    ON a.APP_nm = b.APP_nm
        AND b.start > a.start
WHERE datediff(second, a.end1, b.start) < 10
GROUP BY 1

虽然有效,但在条件失败时不会返回row y

2 个答案:

答案 0 :(得分:0)

有两个原因导致row y未返回是由于条件:

  • b.start > a.start表示一行永远不会自行加入
  • GROUP BY每个APP_nm值只返回一条记录,但所有行都具有相同的值。

但是,查询中还有一些逻辑错误无法成功处理。例如,它如何知道&#34; new&#34;会议开始了?

您所寻找的逻辑可以在普通的PostgreSQL中借助DISTINCT ON函数实现,该函数在特定列中显示每个输入值一行。但是,Redshift不支持DISTINCT ON

一些可能的解决方法:DISTINCT ON like functionality for Redshift

使用编程语言(可以遍历结果并存储变量),您寻找的输出将是微不足道的,但很难应用于SQL查询(设计用于对结果行进行操作)。我建议提取数据并通过一个简单的脚本(例如在Python中)运行,然后输出Start&amp;你寻求的最终组合。

这是Hadoop Streaming function的一个很好的用例,我过去已经成功实现了它。它将记录作为输入,然后记住&#39;开始时间,只有在满足所需的结束逻辑时才输出记录。

答案 1 :(得分:0)

听起来你所追求的是活动事件的“会话化”。您可以使用Windows Functions在Redshift中实现此目的。

完整的解决方案可能如下所示:

SELECT
  start AS session_start,
  session_end
FROM (
       SELECT
         start,
         end1,
         lead(end1, 1)
         OVER (
           ORDER BY end1) AS session_end,
         session_boundary
       FROM (
              SELECT
                start,
                end1,
                CASE WHEN session_switch = 0 AND reverse_session_switch = 1
                  THEN 'start'
                ELSE 'end' END AS session_boundary
              FROM (
                     SELECT
                       start,
                       end1,
                       CASE WHEN datediff(seconds, end1, lead(start, 1)
                       OVER (
                         ORDER BY end1 ASC)) > 10
                         THEN 1
                       ELSE 0 END AS session_switch,
                       CASE WHEN datediff(seconds, lead(end1, 1)
                       OVER (
                         ORDER BY end1 DESC), start) > 10
                         THEN 1
                       ELSE 0 END AS reverse_session_switch
                     FROM app_tax
                   )
                AS sessioned
              WHERE session_switch != 0 OR reverse_session_switch != 0
              UNION
              SELECT
                start,
                end1,
                'start'
              FROM (
                     SELECT
                       start,
                       end1,
                       row_number()
                       OVER (PARTITION BY APP_nm
                         ORDER BY end1 ASC) AS row_num
                     FROM APP_Tax
                   ) AS with_row_number
              WHERE row_num = 1
            ) AS with_boundary
     ) AS with_end
WHERE session_boundary = 'start'
ORDER BY start ASC
;

这是breadkdown(通过子查询名称):

  1. sessioned - 我们首先确定切换行(out和in),其中end和start之间的持续时间超出限制的行。
  2. with_row_number - 只是一个提取第一行的补丁,因为没有切换到它(有一个我们记录为'start'的隐式开关)
  3. with_boundary - 然后我们确定特定开关发生的行。如果您自己运行子查询,则很明显会话在session_switch = 0 AND reverse_session_switch = 1时开始,并在相反的情况下结束。所有其他行都在会话中间,因此会被忽略。
  4. with_end - 最后,我们将'start'/'end'行的结束/开始合并(从而定义会话持续时间),并删除结束行
  5. with_boundary子查询回答了您的初始问题,但通常您希望将这些行组合起来以获得最终结果,即会话持续时间。