2017-06-05 21 views
0

我使用红移方法,并需要相关子查询的替代方案。我得到相关的子查询不支持错误。但是,对于尝试确定同一客户在发起交易给定小时内完成的所有销售交易的特定练习,我不确定传统的左连接是否可行。即,查询取决于来自父级选择的上下文或当前值。我也尝试过使用row_number()窗口函数类似的东西,但同样需要在日期范围上窗口/分区的方式 - 而不仅仅是customer_id。相关子查询的红移替代方案

总体目标是找到给定客户id的第一个销售交易,然后查找在第一个交易60分钟内完成的所有后续交易。对于同一客户(最终是数据库中的所有客户)的其余交易,此逻辑将继续。也就是说,一旦从第一笔交易开始建立了最初的60分钟的窗口,第二个60分钟的窗口将在第一个60分钟的窗口结束时开始,并且第二窗口内的所有交易也将被识别并合并然后重复其余的交易。

输出将列出启动60分钟窗口的第一个事务ID,然后列出在60分钟窗口内创建的其他后续事务ID。第二行将显示同一客户在下一个60分钟窗口中创建的第一个交易ID(同样,第一个60分钟窗口的第一个交易过帐将是第二个60分钟窗口的开始),然后后续交易也进行在第二个60分钟窗口内。

在其最基本的形式查询例子看起来像下面的查询:

select 
s1.customer_id, 
s1.transaction_id, 
s1.order_time, 
(
    select 
     s2.transaction_id 
    from 
     sales s2 
    where 
     s2.order_time > s1.order_time and 
     s2.order_time <= dateadd(m,60,s1.order_time) and 
     s2.customer_id = s1.customer_id 
    order by 
     s2.order_time asc 
    limit 1 
) as sales_transaction_id_1, 
(
    select 
     s3.transaction_id 
    from 
     sales s3 
    where 
     s3.order_time > s1.order_time and 
     s3.order_time <= dateadd(m,60,s1.order_time) and 
     s3.customer_id = s1.customer_id 
    order by 
     s3.order_time asc 
    limit 1 offset 1 
) as sales_transaction_id_2, 
(
    select 
     s3.transaction_id 
    from 
     sales s4 
    where 
     s4.order_time > s1.order_time and 
     s4.order_time <= dateadd(m,60,s1.order_time) and 
     s4.customer_id = s1.customer_id 
    order by 
     s4.order_time asc 
    limit 1 offset 1 
) as sales_transaction_id_3 
from 
    (
     select 
      sales.customer_id, 
      sales.transaction_id, 
      sales.order_time 
     from 
      sales 
     order by 
      sales.order_time desc 
    ) s1; 

例如,如果客户提出了以下交易:

customer_id  transaction_id  order_time   
1234    33453   2017-06-05 13:30 
1234    88472   2017-06-05 13:45 
1234    88477   2017-06-05 14:10 

1234    99321   2017-06-07 8:30 
1234    99345   2017-06-07 8:45 

预期结果将是如下:

customer_id  transaction_id sales_transaction_id_1 sales_transaction_id_2 sales_transaction_id_3 
1234    33453   88472     88477     NULL 
1234    99321   99345     NULL     NULL 

而且,它出现红移不支持横向联接这似乎以进一步限制我选择的方案。任何帮助将不胜感激。

+2

编辑你的问题,并提供样本数据和预期的结果。 。 。以及逻辑应该做什么的解释。 –

+0

他们是否支持窗口函数? CTE的?顺便说一句:你只是从's1'中选择,所以查询的另外两条腿可以用'EXISTS(...)'代替(摆脱丑陋的LIMIT 1) – wildplasser

+1

combined_transaction_id_1同时用作别名和列这是令人困惑的,因为@GordonLinoff说请提供样本数据以及你想要做什么。 – sia

回答

0

从你的描述中,你只需要group by和某种日期差异。我不知道你怎么想的行结合起来,但这里的基本思想是:

select s.customer_id, 
     min(order_time) as first_order_in_hour, 
     max(order_time) as last_order_in_hour, 
     count(*) as num_orders 
from (select s.*, 
      min(order_time) over (partition by customer_id) as min_ot 
     from sales s 
    ) s 
group by customer_id, floor(datediff(second, min_ot, order_time)/(60 * 60)); 

这一提法(或类似的东西,因为Postgres没有datediff())也将在Postgres的要快得多。

+0

这是正确的轨道,但是,单个transaction_ids需要明确列出。也就是说,落在特定60分钟窗口内的交易ID需要被保留,而不是立即通过分组汇总。 – user3701000

+0

@ user3701000。 。 。然后移除'group by'并做任何你需要的事情。这是你需要的想法。 –

+0

有或没​​有分组时,这仍然包括所有交易。相反,第一个事务将被识别,列出在该特定的60分钟窗口内的所有后续事务id,然后跳到下一个60分钟窗口并且执行相同的操作 - 即列出所有事务(不列出来自先前窗口的事务)第二个60分钟的窗口等等。 – user3701000

0

您可以使用窗口函数来获取每个事务的后续事务。该窗口将是客户/小时,你可以记录排序得到的第一个“锚”的交易,并得到你所需要的所有后续交易:

with 
transaction_chains as (
    select 
    customer_id 
    ,transaction_id 
    ,order_time 
    -- rank transactions within window to find the first "anchor" transaction 
    ,row_number() over (partition by customer_id,date_trunc('minute',order_time) order by order_time) 
    -- 1st next order 
    ,lead(transaction_id,1) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_1 
    ,lead(order_time,1) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_1 
    -- 2nd next order 
    ,lead(transaction_id,2) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_2 
    ,lead(order_time,2) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_2 
    -- 2nd next order 
    ,lead(transaction_id,3) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_3 
    ,lead(order_time,3) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_3 
    from sales 
) 
select 
customer_id 
,transaction_id 
,transaction_id_1 
,transaction_id_2 
,transaction_id_3 
from transaction_chains 
where row_number=1;