2016-04-11 18 views
0

私はここでかなり明白な何かを見逃していると思います。MySQLのWHERE句の結果を比較する

私は総額が予約の合計金額よりも高い「予約」のリストを表示しようとしています。料金と支払いは、外部キーを使用してリンクされた別々のテーブルに格納されます。これまで

私のクエリです:

SELECT `booking`.`id`, 
SUM(`booking_charge`.`amount`) AS `charges`, 
SUM(`booking_payment`.`amount`) AS `payments` 

FROM `booking` 
LEFT JOIN `booking_charge` ON `booking`.`id` = `booking_charge`.`booking_id` 
LEFT JOIN `booking_payment` ON `booking`.`id` = `booking_payment`.`booking_id` 

WHERE `charges` > `payments` ///this is the incorrect part 

GROUP BY `booking`.`id` 

私のテーブルはこのような何かを見て:

Booking (ID) 

Booking_Charge (Booking_ID, Amount) 

Booking_Payment (Booking_ID, Amount) 

をMySQLのは、これら2つのテーブルの結果を比較したいとしていないようです、私は何が欠けているのか分からないが、それは可能なことだと確信している。

+0

エラーはありません?、名前はあいまいではありませんか? – Saikios

+0

私はそれも、 'booking_charge'と' booking_payment'テーブル名を 'amount'の前に置くことになったと思いました。 しかし、それはいずれにせよ役立たないようです。 SQLは 'where句'のUnknownカラム 'charges'について不平を言っています...なぜなら、 'charges 'はクエリ自体の間にカラムとして作成されるからです。 –

+0

最後に「WHERE charges> payments'を削除し、「HAVING charges> payments」を追加してください。 –

答えて

1

ようなHAVINGの代わりWHEREを試すには、クロス `_payment`から` _charge`と行からの行の間の結合です。これは半デカルト結合です。 `_charge`から返された各行は、` _payment`から返された各行と、指定された `booking_id`に対してマッチします。

は、簡単な例を考えてみましょう:

はのは、特定の `booking_id`のための$ 40のために_charge``で単一行を入れてみましょう。

そして、同じ `booking_id`に対して、2つの行をそれぞれ$ 20の` _payment`に入れます。

クエリは$ 80の合計料金を返します。 (= 2×40ドル)。代わりに5ドルの行が$ 10ずつ5ドルであれば、クエリは$ 200(= 5×40ドル)の合計費用を返します

この問題に対処する方法はいくつかあります。 1つのアプローチは、インラインビューで集約を行い、各booking_idの料金と支払いの合計を単一の行として返し、それらを予約テーブルに追加することです。 booking_idごとに最大で1つの行がある場合、クロスジョインは_chargeおよび/または_paymentから行を「複製する」問題を生じません。例えば

SELECT b.id 
     , IFNULL(c.amt,0) AS charges 
     , IFNULL(p.amt,0) AS payments 
    FROM booking b 
    LEFT 
    JOIN (SELECT bc.booking_id 
       , SUM(bc.amount) AS amt 
      FROM booking_charge bc 
      GROUP BY bc.booking_id 
     ) c 
     ON c.booking_id = b.id 
    LEFT 
    JOIN (SELECT bp.booking_id 
       , SUM(bp.amount) AS amt 
      FROM booking_payment bp 
      GROUP BY bp.booking_id 
     ) p 
     ON p.booking_id = b.id 
    WHERE IFNULL(c.amt,0) > IFNULL(p.amt,0) 

私たちは、WHEREの代わりに、HAVING句の使用を作ることができます。


この回答のクエリは、結果を得るための唯一の方法でも、最も効率的でもありません。同等の結果を返す他のクエリパターンがあります。

+0

ありがとうございました。あなたが気づいたことに感謝しています。私のテストではあなたが言及した前の問題に気付かなかったかもしれないと心配しています。私は値の範囲でそれをテストし、それは完全に動作するようです。再度、感謝します! –

1

クエリでの問題のこの

SELECT `booking`.`id`, 
SUM(`booking_charge`.`amount`) AS `charges`, 
SUM(`booking_payment`.`amount`) AS `payments` 
FROM `booking` 
LEFT JOIN `booking_charge` ON `booking`.`id` = `booking_charge`.`booking_id` 
LEFT JOIN `booking_payment` ON `booking`.`id` = `booking_payment`.`booking_id` 
GROUP BY `booking`.`id` 
HAVING `charges` > `payments` 
+0

私は存在していても完璧に働いていることは知らなかった。どうもありがとうございます! –

+0

これは、_ chargeと_booking間のクロス結合(部分デカルト積)の悪質な問題には対処しません。また、指定されたbooking_idに対して_payment(amountの値がnullでない行)がない場合(この問合せではその行は戻されません)は対処されません。 – spencer7593

+0

ありがとう@ spencer7593 - 私はあまりにも実際にその問題にぶつかった、私は興奮でそれについて忘れていた。 私の回避策は、ちょうど使用することでした:ifnull(SUM( 'booking_charge'.amount')、0)AS' charges'、 ifnull(SUM( 'booking_payment'.amount')、0)' payments' 、 –

関連する問題