2017-06-05 28 views
0

Redshiftを使用しており、相関サブクエリの代替手段が必要です。相関サブクエリがサポートされていないエラーが表示されます。ただし、元の取引から一定時間内に同じ顧客によって行われたすべての販売取引を特定しようとするこの特定の行使の場合、従来の左参入がどちらも有効かどうかはわかりません。つまり、クエリは、親セレクトのコンテキストまたは現在の値に依存します。私もrow_number()ウィンドウ関数を使用して同様のものを試しましたが、再びcustomer_idではなく、日付範囲のウィンドウ/パーティションへの道が必要です。相関サブクエリの代替Redshift

全体的な目標は、特定の顧客IDの最初の販売取引を見つけ、最初の取引から60分以内に行われたすべての後続取引を見つけることです。このロジックは、同じ顧客(および最終的にはデータベース内のすべての顧客)の残りのトランザクションに対して引き続きオンになります。つまり、最初のトランザクションの時間から最初の60分のウィンドウが確立されると、最初の60分のウィンドウの最後に2番目の60分のウィンドウが始まり、2番目のウィンドウ内のすべてのトランザクションも識別され、結合されますその後、残りのトランザクションについても繰り返します。

出力には、60分のウィンドウを開始した最初のトランザクションIDと、60分のウィンドウ内に作成された後続のトランザクションIDが表示されます。 2番目の行には、次の60分のウィンドウで同じ顧客が行った最初のトランザクションIDが表示されます(最初の60分のウィンドウが2番目の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 

また、Redshiftは外見のような横結合をサポートしていないようです私の処分でオプションをさらに制限することができます。どんな助けでも大歓迎です。

+2

質問を編集し、サンプルデータと希望する結果を提供してください。 。 。論理が何をしているのかについての説明。 –

+0

ウィンドウ関数をサポートしていますか? CTEs? BTW:あなたは 's1'からのみ選択しているので、クエリの他の2つの脚は' EXISTS(...) 'で置き換えることができます(醜いLIMIT1も取り除きます) – wildplasser

+1

combined_transaction_id_1は、エイリアスとカラム@GordonLinoffがサンプルデータと正確に何をしたいのかを教えてください。 – sia

答えて

0

あなたの説明から、group byと日付の違いがほしいと思うだけです。私はあなたが行を組み合わせたいかどうかはわかりませんが、ここでは基本的な考え方である:(Postgresはdatediff()を持っていないためか、似たような)

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の中ではるかに高速になります。

+0

これは正しいことですが、個別のtransaction_idsを明示的にリストする必要があります。つまり、特定の60分のウィンドウ内にあるトランザクションIDは保存され、グループ別に即座に集計される必要はありません。 – user3701000

+0

@ user3701000。 。 。その後、 'group by'を削除し、必要な処理をします。これはあなたが必要とするもののためのアイデアです。 –

+0

グループの有無にかかわらず、これには依然としてすべてのトランザクションが含まれます。その代わりに、最初のトランザクションが特定され、その特定の60分のウィンドウ内のすべての後続のトランザクションIDがリストされ、次に60分のウィンドウにスキップされ、同じことが実行されます。 2番目の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; 
関連する問題