1

以下に示す 2 つのクエリがあります。クエリは同じテーブルを選択しますが、条件と列数が異なります。これらを組み合わせる方法を解決できません。何か方法はありますか?

最初のクエリは次のとおりです。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 1, 1, 0)) filled
  FROM tableA a,
       tableB b
 WHERE a.branchCode = b.branchCode
   AND a.registerNumber IN (SELECT c.registerNumber
                              FROM tableC c
                             WHERE c.registerDate <= '01.02.2013'
                               AND c.state = 'A'
                               AND c.contractState != 2)
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type;

結果は次のようになります。

BranchNumber     CountryCode    Type Filled
1452                 USA          0    5
1452                 USA          2    8
1452                 USA          1    16
7854                 GER          0    10
7854                 GER          1    3

2 番目のクエリは次のとおりです。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 0, 1, 0)) free, 
       SUM(DECODE(a.status, 2, 1, 0)) damaged    
  FROM tableA a,
       tableB b  
 WHERE a.kks_kayitdrm = 'A'    
   AND a.branchCode = b.branchCode    
   AND a.recordDate <= '01.02.2013'  
 GROUP BY b.centerBranchNumber,
           a.type,
           b.countryCode;

結果は次のとおりです。

BranchNumber     CountryCode    Type Free     Damage
1452                 USA          0    5        2  
1452                 USA          2    8        1  
1452                 USA          1    16       5
7854                 GER          0    10       9  
7854                 GER          1    3        16

組み合わせると、次のような結果が必要になります。

BranchNumber     CountryCode    Type   Filled    Free     Damage
1452                 USA          0      1         5        2  
1452                 USA          2      2         8        1  
1452                 USA          1      65        16       5
7854                 GER          0      7         10       9  
7854                 GER          1      45        3        16   
4

1 に答える 1

1

最初のクエリは次のように書き直すことができます。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 1, 1, 0)) filled
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE c.registerDate <= '01.02.2013'
   AND c.state = 'A'
   AND c.contractState != 2
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type

秒を ANSI 構文に変換すると (何か間違ったことをしたときに非常に明白になるため、より複雑なクエリに役立ちます)、次のようになります。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 0, 1, 0)) free, 
       SUM(DECODE(a.status, 2, 1, 0)) damaged    
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode      
 WHERE a.kks_kayitdrm = 'A'
   AND a.recordDate <= '01.02.2013'  
 GROUP BY b.centerBranchNumber,
           a.type,
           b.countryCode

ご覧のとおり、2 つのクエリには多くの類似点があります。必要な結果セットを取得するには、2 つの方法があります。類似していない条件を SUM の CASE ステートメントに移動します。または、2 つのクエリを UNION ALL して、再度合計することもできます。しなければならない作業の量を減らすため、CASE ステートメントを使用することをお勧めします。欠点は、クエリが読みにくくなることです。

クエリの共通部分は次のとおりです。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode 
 GROUP BY b.centerBranchNumber,
          a.type,
          b.countryCode

これをベースとして、同じ結果が得られるまでゆっくりと追加できます。同じ結果が得られるように、同じ条件を WHERE / JOINS に追加することを忘れないでください。

最初にすべての条件を追加すると、最初のクエリで tableC の JOIN を LEFT OUTER JOIN に変更する必要があります。これは、WHERE 句が結果セットを INNER JOIN のように制限するのとまったく同じです。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE c.registerDate <= '01.02.2013'
   AND c.state = 'A'
   AND c.contractState != 2
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type

2 番目のクエリに条件を追加すると、WHERE 句に OR が必要になります。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE ( c.registerDate <= '01.02.2013'
         AND c.state = 'A'
         AND c.contractState != 2 
             )
    OR ( a.kks_kayitdrm = 'A'
         AND a.recordDate <= '01.02.2013' 
             )
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type

次に、あなたの日付は少し奇妙に思えます。文字列リテラルを日付に変換していないようです'01.02.2013'。YYYYMMDD の形式ではないため、比較は機能しません。NLS_DATE_FORMATがフォームであることに依存してDD.MM.YYYYいますが、これはすべてのセッションで保証できません。日付を比較するには、組み込みTO_DATE()関数を使用して明示的に変換するか、適切な形式モデルを使用するか、ANSI日時リテラルを使用する必要があります。これについては、この回答で詳しく説明しています。

次の理由から、Oracleは暗黙的な変換を使用しないことを明示的に推奨していると言えます。

  • 明示的なデータ型変換関数を使用すると、SQL ステートメントが理解しやすくなります。

  • 暗黙的なデータ型変換は、特に列値のデータ型が定数のデータ型に変換される場合、逆ではなく、パフォーマンスに悪影響を与える可能性があります。

  • 暗黙的な変換は、それが発生するコンテキストに依存し、すべての場合で同じように機能するとは限りません。たとえば、日時値から VARCHAR2 値への暗黙的な変換では、 NLS_DATE_FORMAT パラメータの値によっては予期しない年が返される場合があります。

  • 暗黙的な変換のアルゴリズムは、ソフトウェア リリース間および Oracle 製品間で変更される可能性があります。明示的な変換の動作はより予測可能です。

したがって、日付を比較するには、TO_DATE() を使用することをお勧めします。たとえば、次のようになります。

WHERE ( c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy')

最後に、SUM を追加できます。これは、それらの中で以前の条件を繰り返すことを意味します。何かが「満たされている」かどうかは LEFT OUTER JOIN のみに依存するため、最初のクエリでこれを単純化できます。つまりregisterNumber、JOIN 内のそのテーブルの が null でない場合、条件は真です。

どちらの場合も、DECODE ではなく CASE ステートメントを使用します。これは、 CASE がはるかに強力であり、DECODE では保証されていない正しいデータ型を強制するためです。

これらすべてをまとめると、最終的なクエリは次のようになります。

SELECT b.centerBranchNumber
     , b.countryCode
     , a.type
     , sum(case when a.status = 1 and c.registernumber is not null then 1
                else 0
           end) as filled
     , sum(case when a.status = 0 
                     and a.kks_kayitdrm = 'A'
                     and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
                     then 1
                else 0
           end) as free
     , sum(case when a.status = 2
                     and a.kks_kayitdrm = 'A'
                     and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
                     then 1
                else 0
           end) as damaged
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE ( c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy')
         AND c.state = 'A'
         AND c.contractState != 2 
             )
    OR ( a.kks_kayitdrm = 'A'
         AND a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
             )
 GROUP BY b.centerBranchNumber
        , b.countryCode
        , a.type

必要に応じて、このアプローチをより一般的に使用してクエリを組み合わせることができます。

于 2013-02-05T08:44:38.633 に答える