file_id
対処する必要がある 1 つの問題は、1 つまたは複数のクエリによって返される特定の行がない場合に、これらのクエリの 1 つが「ドライバー」になるかどうかです。(たとえば、 からの行はあるかもしれませんが、 からsess
の行はありませんfile_payments
。任意のクエリに表示されるすべての可能なものを確実に含めたい場合は、次のようなクエリでfile_id
可能なすべてのリストを取得できます。file_id
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
(注: UNION 演算子は重複を削除します)
指定された結果セットを取得するには、そのクエリを他の 3 つの元のクエリの「左結合」と共に使用できます。クエリの概要は次のとおりです。
SELECT a.file_id, p.total_payment - ( s.total + c.total_charges)
FROM a
LEFT JOIN s ON s.file_id = a.file_id
LEFT JOIN c ON c.file_id = a.file_id
LEFT JOIN p ON p.file_id = a.file_id
ORDER BY a.file_id
そのステートメントa
には、すべての値のセットを取得するクエリの代用がありfile_id
ます (上記を参照)。s
とはc
、p
それぞれ sess、file_charges、file_payments に関する 3 つの元のクエリの代用です。
いずれかfile_id
のクエリで値が「欠落」している場合は、欠落している値をゼロに置き換える必要があります。IFNULL 関数を使用して、それを処理できます。
このクエリは、指定された結果セットを返す必要があります。
SELECT a.file_id
, IFNULL(p.total_payment,0) - ( IFNULL(s.total,0) + IFNULL(c.total_charges,0)) AS t
FROM ( -- all possible values of file_id
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
LEFT
JOIN ( -- the amount that a specific student should pay
SELECT sess.file_id, SUM(sess.rate * sess.length) AS total
FROM sess
WHERE sess.sessionDone = 1
GROUP BY sess.file_id
) s
ON s.file_id = a.file_id
LEFT
JOIN ( -- charges
SELECT file_charges.file_id, SUM(file_charges.price) AS total_charges
FROM file_charges
GROUP BY file_charges.file_id
) c
ON c.file_id = a.file_id
LEFT
JOIN ( -- payments
SELECT file_payments.file_id, SUM(file_payments.paymentAmount) AS total_payment
FROM file_payments
GROUP BY file_payments.file_id
) p
ON p.file_id = a.file_id
ORDER BY a.file_id
(このクエリの EXPLAIN は、派生テーブルが 4 つあるため、見栄えがよくありません。非常に大きなセットでは、パフォーマンスが大幅に低下する可能性があります。ただし、返される結果セットは仕様を満たす必要があります。)
3 つのテーブルすべてを JOIN するクエリに注意してください。(たとえば) テーブルに同じ行が 2 つ (またはそれ以上) ある場合、誤った結果が返される可能性がありfile_id
ますfile_payment
。
同等の結果セットを取得する方法は他にもありますが、上記のクエリは、「これらのクエリの結果を合計に結合するにはどうすればよいか」という質問に答えています。
相関サブクエリの使用
SELECT リストで相関サブクエリを使用する別のアプローチを次に示します...
SELECT a.file_id
, IFNULL( ( SELECT SUM(file_payments.paymentAmount) FROM file_payments
WHERE file_payments.file_id = a.file_id )
,0)
- ( IFNULL( ( SELECT SUM(sess.rate * sess.length) FROM sess
WHERE sess.file_id = a.file_id )
,0)
+ IFNULL( ( SELECT SUM(file_charges.price) FROM file_charges
WHERE file_charges.file_id = a.file_id )
,0)
) AS tot
FROM ( -- all file_id values
SELECT ss.file_id FROM sess ss
UNION
SELECT fc.file_id FROM file_charges fc
UNION
SELECT fp.file_id FROM file_payments fp
) a
ORDER BY a.file_id