0

以下のようなマスターテーブルと参照テーブルがあります。

WITH MAS as (
SELECT 10 as CUSTOMER_ID, 1 PROCESS_ID, 44 PROCESS_TYPE, 200 as AMOUNT FROM DUAL UNION ALL
SELECT 10 as CUSTOMER_ID, 1 PROCESS_ID, 44 PROCESS_TYPE, 250 as AMOUNT FROM DUAL UNION ALL
SELECT 10 as CUSTOMER_ID, 2 PROCESS_ID, 45 PROCESS_TYPE, 300 as AMOUNT FROM DUAL UNION ALL
SELECT 10 as CUSTOMER_ID, 2 PROCESS_ID, 45 PROCESS_TYPE, 350 as AMOUNT FROM DUAL 
), REFTAB as (
SELECT 44 PROCESS_TYPE, 'A' GROUP_ID FROM DUAL UNION ALL 
SELECT 44 PROCESS_TYPE, 'B' GROUP_ID FROM DUAL UNION ALL
SELECT 45 PROCESS_TYPE, 'C' GROUP_ID FROM DUAL UNION ALL 
SELECT 45 PROCESS_TYPE, 'D' GROUP_ID FROM DUAL
) SELECT ...

select正しく機能する私の最初のステートメントは次のとおりです。

SELECT CUSTOMER_ID,
       SUM(AMOUNT) as AMOUNT1,
       SUM(CASE WHEN PROCESS_TYPE IN (SELECT PROCESS_TYPE FROM REFTAB WHERE GROUP_ID = 'A') 
                THEN AMOUNT ELSE NULL END) as AMOUNT2,
       COUNT(CASE WHEN PROCESS_TYPE IN (SELECT PROCESS_TYPE FROM REFTAB WHERE GROUP_ID = 'D') 
                  THEN 1 ELSE NULL END) as COUNT1
   FROM MAS
  GROUP BY CUSTOMER_ID

ただし、パフォーマンスの問題に対処するために、次のselectステートメントに変更しました。

SELECT CUSTOMER_ID,
       SUM(AMOUNT) as AMOUNT1,
       SUM(CASE WHEN GROUP_ID = 'A' THEN AMOUNT ELSE NULL END) as AMOUNT2,
       COUNT(CASE WHEN GROUP_ID = 'D' THEN 1 ELSE NULL END) as COUNT1
   FROM MAS A
   LEFT JOIN REFTAB B ON A.PROCESS_TYPE = B.PROCESS_TYPE
  GROUP BY CUSTOMER_ID

AMOUNT2およびCOUNT1列の値は同じままです。ただし、AMOUNT1は参照テーブルとの結合のため、値が乗算されます。

の追加の結合条件を使用して、さらに 1 つの左結合を追加できることはわかっていGROUP_IDます。しかし、それはサブクエリを使用することと何ら変わりはありません。

値を乗算せずに、左結合を 1 つだけ使用してクエリを機能させる方法はありAMOUNT1ますか?

4

3 に答える 3

0

追加の GROUP_ID 句を追加して左結合をもう 1 つ追加できることはわかっていますが、サブクエリと変わらないでしょう。

あなたは驚かれることでしょう。サブクエリの代わりに 2 つの左結合を使用するとSELECT、オプティマイザがクエリを最適化する方法が増えます。私はまだそれを試してみます:

select m.customer_id,
       sum(m.amount) as amount1,
       sum(case when grpA.group_id is not null then m.amount end) as amount2,
       count(grpD.group_id) as count1
  from mas m
  left join reftab grpA
    on grpA.process_type = m.process_type
   and grpA.group_id = 'A'
  left join reftab grpD
    on grpD.process_type = m.process_type
   and grpD.group_id = 'D'
 group by m.customer_id

重複値の問題を回避するために、SUM()分析関数を使用して結合amount1に値を計算する次のクエリを試すこともできます。

select m.customer_id,
       m.customer_sum as amount1,
       sum(case when r.group_id = 'A' then m.amount end) as amount2,
       count(case when r.group_id = 'D' then 'X' end) as count1
  from (select customer_id,
               process_type,
               amount,
               sum(amount) over (partition by customer_id) as customer_sum
          from mas) m
  left join reftab r
    on r.process_type = m.process_type
 group by m.customer_id,
          m.customer_sum

両方のオプションをテストして、どちらが優れているかを確認できます。

于 2015-09-22T13:30:25.513 に答える
0

IN元のクエリから始めて、クエリをステートメントに置き換えるだけでEXISTS、大幅な向上が得られます。また、合計NULLs に注意してください。おそらくあなたのELSEステートメントは0?

SELECT CUSTOMER_ID,
       SUM(AMOUNT) as AMOUNT1,
       SUM(CASE WHEN EXISTS(SELECT 1 FROM REFTAB WHERE REFTAB.GROUP_ID = 'A' AND REFTAB.PROCESS_TYPE = MAS.PROCESS_TYPE)
                THEN AMOUNT ELSE NULL END) as AMOUNT2,
       COUNT(CASE WHEN EXISTS(SELECT 1 FROM REFTAB WHERE REFTAB.GROUP_ID = 'D' AND REFTAB.PROCESS_TYPE = MAS.PROCESS_TYPE) 
                  THEN 1 ELSE NULL END) as COUNT1
   FROM MAS
  GROUP BY CUSTOMER_ID
于 2015-09-22T20:51:17.440 に答える
0

通常の方法は、 の前に値を集計することですgroup by。残りのクエリが正しい場合は、条件付き集計を使用することもできます。

SELECT CUSTOMER_ID,
       SUM(CASE WHEN seqnum = 1 THEN AMOUNT END) as AMOUNT1,
       SUM(CASE WHEN GROUP_ID = 'A' THEN AMOUNT ELSE NULL END) as AMOUNT2,
       COUNT(CASE WHEN GROUP_ID = 'D' THEN 1 ELSE NULL END) as COUNT1
FROM MAS A LEFT JOIN
     (SELECT B.*, ROW_NUMBER() OVER (PARTITION BY PROCESS_TYPE ORDER BY PROCESS_TYPE) as seqnum
      FROM REFTAB B
     ) B
     ON A.PROCESS_TYPE = B.PROCESS_TYPE
GROUP BY CUSTOMER_ID;

これにより、結合によって作成された重複が無視されます。

于 2015-09-22T11:19:33.803 に答える