0

私はSQLの初心者であり、クエリについて疑問があります。

私は3つのテーブルを持っています:

  1. フィールドcons_id_no、key_idを持つコンシューマー
  2. key_id、bill_id_no、amt_payable、bill_dateの各フィールドを持つbm_bill(すべての請求額と消費者の日付が含まれます)
  3. key_id、receipt_no、amt_paid、fine、pay_dateのフィールドを持つmreceipt(消費者のすべての支払いの詳細が含まれます)

コンシューマーテーブルは、bm_billおよびmreceiptと1対多の関係があります。cons_id_noに基づいて消費者の元帳情報を作成したいと思います。これには、彼のcons_id_no、key_id、bill_id_no(最新)、bill_date(最新)、amt_payable(最新)、receipt_no(最新)、amt_paid(最新)、fine(最新)、pay_date(最新)が含まれている必要があります。クエリ

SELECT 
   c.key_id,
   c.cons_id_no consumerid, 
   b.bill_id_no billno,
   TO_CHAR(b.bill_date,'dd-Mon-YYYY') billdate,
   b.amt_payable,
   m.receipt_no receiptno, 
   TO_CHAR(m.pay_date,'dd-Mon-YYYY') paydate,
   m.amt_paid+m.fine amountpaid 
FROM 
   consumer c 

   LEFT OUTER JOIN (SELECT key_id, MAX(bill_date) AS maxDate FROM bm_bill GROUP BY key_id) maxBillDate 
   ON (maxBillDate.key_id = c.key_id)

   LEFT OUTER JOIN bm_bill b 
   ON (b.key_id = c.key_id AND b.bill_date = maxBillDate.maxDate) 

   LEFT OUTER JOIN (SELECT key_id, MAX(pay_date) AS maxPayDate FROM mreceipt GROUP BY key_id) maxMReceipt 
   ON (maxMReceipt.key_id = c.key_id)

   LEFT OUTER JOIN mreceipt m 
   ON (m.key_id = c.key_id AND m.pay_date = maxMReceipt.maxPayDate)

WHERE 
   c.cons_id_no='?';

クエリを実行すると、目的の結果が得られました。次に、クエリが遅すぎることに気づき、私のソリューションでは次のことがわかりました。

SELECT key_id, max(bill_date) AS maxDate FROM bm_bill GROUP BY key_id

これは、特定のkey_idの情報のみが必要なbm_billからすべてのkey_idsとbill_datesを取得しています。とりわけ、私のソリューションには、このようなクエリがもう1つあります。

したがって、私の質問は次のとおりです。これを行うためのより良い方法はありますか?

4

4 に答える 4

2

2つのテーブル(bm_billとmreceipt)のそれぞれを2回結合しています。最初に試すのは、二重結合を回避するようにクエリを変更し、それが違いを生むかどうかを確認することです。

SELECT 
   c.key_id,
   c.cons_id_no consumerid, 
   b.bill_id_no billno,
   TO_CHAR(b.bill_date,'dd-Mon-YYYY') billdate,
   b.amt_payable,
   m.receipt_no receiptno, 
   TO_CHAR(m.pay_date,'dd-Mon-YYYY') paydate,
   m.amt_paid+m.fine amountpaid 
FROM 
   consumer c 

   LEFT JOIN (SELECT key_id,
   bill_id_no, bill_date,amt_payable,receipt_no receiptno , 
   ROW_NUMBER() OVER (PARTITION BY key_id ORDER BY bill_date DESC) as rn
   FROM bm_bill)b ON (b.key_id = c.key_id and b.rn =1)


   LEFT JOIN (SELECT key_id,
   pay_date , amt_paid, amt_paid, fine, 
   ROW_NUMBER() OVER (PARTITION BY key_id ORDER BY pay_date DESC) as rn
   FROM mreceipt) m ON (m.key_id = c.key_id and m.rn =1)


WHERE 
   c.cons_id_no='?';

それがうまく機能しない場合は、SQLServerの「代替」であるOracleを使用して回避できます。それぞれをOUTER APPLY返す2つの関数を作成し、それらを結合します。MAX(bill_date)MAX(pay_date)

于 2013-03-22T16:56:19.320 に答える
0

1-を使用する代わりに、を使用してデータを使用し、;の代わりに関数を使用MAXすることをお勧めします。また、の代わりに。を使用します。ORDERDESCGROUPTOPMAXLEFT JOINWHERE X IN (...)

2-データの大きさはわかりませんが、数千万行の場合は、グループ化された結果を一時的にインデックス付きのテーブルに保存すると、処理時間が改善される可能性があります。

3-また、このクエリを実行する必要がある頻度(鮮度のレベル)も関係します。過去数分間の最新の結果(ではなく、その日の結果)が必要ない場合は、必ず一時ストレージを使用してください。その日のすべてのクエリに使用できます。

于 2013-03-22T16:38:20.657 に答える
0

クエリをそのまま使用すると、目的の結果が得られるとおっしゃいました。その場合は、次のことを考慮してください。

派生テーブル(maxBillDate)に参加していますが、どのような目的で使用しますか?結合をフィルターとして使用していないか、テーブル内のフィールドを使用していません。だから...それを取り除き、クエリを再実行すると、それがなくても同じ結果が得られることがわかります。

...派生テーブルと同じストア:maxReceipt

そこから始めて、不要な荷物を取り除き、あなたの考えを見てください。

于 2013-03-22T16:49:34.533 に答える
0

素晴らしい質問です!ROW_NUMBERこれは、またはのような分析関数を求めていたため、大変でしたRANKが、2つの外部結合は複雑なものでした。DENSE_RANKしかし、トリックをしました。これが私が思いついたものです:

select * from (
  select
    c.key_id,
    c.cons_id_no consumerid,
    to_char(m.pay_date, 'dd-Mon-YYYY') paydate,
    m.receipt_no receiptno,
    m.amt_paid+m.fine amountpaid,
    dense_rank() over
      (order by m.pay_date desc nulls last) as paydaterank,
    to_char(b.bill_date, 'dd-Mon-YYYY') billdate,
    b.bill_id_no billno,
    b.amt_payable,
    dense_rank() over
      (order by b.bill_date desc nulls last) as billdaterank
 from customer c
 left outer join mreceipt m on c.key_id = m.key_id
 left outer join bm_bill b on c.key_id = b.key_id
 where c.cons_id_no = '?'
)
where paydaterank = 1 and billdaterank = 1

私はこれを次の条件でテストしました。

  1. bm_billには複数の関連する行があり、mreceiptには関連する行がありませんでした
  2. mreceiptには複数の関連する行があり、bm_billには行がありませんでした
  3. bm_billとmreceiptには関連する行がありました

いずれの場合も機能しましたが、このように根本的に書き直すと、さらにテストする必要があります。

また、これを理解するために日付とIDに焦点を合わせ、後で他のすべての列を追加したことにも注意してください。列のリストにタイプミスや脱落がないか確認してください。すべてを入力した後、簡単に確認しましたが、何かを見逃している可能性があります。

于 2013-03-22T17:42:31.727 に答える