2017-06-30 3 views
0

私のスクリプトは動作しているはずだが、それは効率的ではないかもしれないし、主な問題は私が仕事でそれを実行するには時間がかかり過ぎていると思う、セッションが終了する前に全セッションが中止されています。SQLスクリプトを最適化する:別のテーブルから範囲値を取得する

私は基本的に2つのテーブル 表A持っている - 人は

Person's_ID Transaction TransactionDate 
--------------------------------------- 
123    A   01/01/2017 
345    B   04/06/2015 
678    C   13/07/2015 
123    F   28/10/2016 

表Bを行うすべての取引が含まれている - 個人のIDが含まれていますし、私が何をしたいのかGraduationDate

は人がアクティブであるかどうかを確認です。 アクティブ=卒業予定日の1ヶ月前に相手が行った取引が1件以上の場合

私は何百万人もの人がいて、各人が複数の取引を行い、表Aの行は

SELECT 
PERSON_ID 
FROM 
    (SELECT PERSON_ID, TRANSACTIONDATE FROM TABLE_A) A 
LEFT JOIN 
    (SELECT CIN, GRAD_DATE FROM TABLE_B) B 
ON A.PERSON_ID = B.PERSON_ID 
AND TRANSACTIONDATE <= GRAD_DATE 
WHERE TRANSACTIONDATE BETWEEN GRAD_DATE - INTERVAL '30' DAY AND GRAD_DATE; 

*表AとBはサブクエリです。

+0

出力はどのようになりますか? –

+0

FYIと同様に、where句は内部結合になります。実際に外部結合が必要な場合は、where節をon節に移動する必要があります。 – Andrew

+0

こんにちは@GordonLinoff、私が期待しているのは、 "アクティブ"なPERSON_IDのリストです - これは、人のそれぞれの卒業予定日から30日以内にトランザクションを意味します。 – Joy

答えて

0

あなただけのアクティブな顧客をしたい場合は、私はexistsをしようとするだろう:

SELECT PERSON_ID 
FROM TABLE_A A 
WHERE EXISTS (SELECT 1 
       FROM TABLE_B B 
       WHERE A.PERSON_ID = B.PERSON_ID AND 
        A.TRANSACTIONDATE BETWEEN B.GRAD_DATE - INTERVAL '30' DAY AND GRAD_DATE 
      ); 

パフォーマンスは、しかし、あなたのクエリに類似である可能性が高いです。テーブルが本当にテーブルだったら、私はインデックスを提案します。実際には、おそらくビューを理解する必要があるため(よりよいインデックスを作成できるように)、または一時テーブルを使用する必要があります。

+0

ありがとう、@ GordonLinoff、これを調べようとしています。それは完全に実行されます!私の元のスクリプトよりも速い。今の結果を見てください。 – Joy

0

非等結合(それが存在する参加したりないようにコーディングだ場合に関係なく)、非常に非効率的かもしれないが、ロジックがに書き換えることができます。これは、一つだけの行があることを前提としてい

SELECT 
    PERSON_ID 
FROM 
(-- combine both Selects 
    SELECT 0 AS flag -- indicating source table 
     PERSON_ID, TRANSACTIONDATE AS dt 
    FROM TABLE_A 
    UNION ALL 
    SELECT 1 AS flag, 
     PERSON_ID, GRAD_DATE 
    FROM TABLE_B 
) A 
QUALIFY 
    flag = 1 -- only return a row from table B 
AND Min(dt) -- if the previous row (from table A) is within 30 days 
    Over (PARTITION BY PERSON_ID 
      ORDER BY dt, flag 
      ROWS BETWEEN 1 Preceding AND 1 Preceding) >= dt - 30 

テーブルAの人数より多い場合はMINを次のように変更する必要があります。

AND MAX(CASE WHEN flag = 1 THEN dt END) -- if the previous row (from table A) is within 30 days 
    Over (PARTITION BY PERSON_ID 
      ORDER BY dt, flag 
      ROWS UNBOUNDED Preceding) >= dt - 30 
+0

こんにちは@dnoeth、ありがとう!私は現在、抽出されたデータが正しいかどうかを検証しています。しかし理解するだけで、min(dt)は30日以内にどのようにキャプチャすることができますか?その取引は、その卒業日から30日以内に行わなければならない。ご協力いただきありがとうございます! – Joy

+0

@Joy: 'MIN 'は単に'前の '行(' MAX'でもあった可能性があり、結果はStandard SQLの 'LAG'と同等です)を見て、それを現在の行と比較します。 table_Aの行は前の行に最新の日付が格納されています(1人あたり行が1つしかないと仮定すると、それ以外の場合はMINを変更する必要があります) – dnoeth

関連する問題