需要解决的一个问题是这些查询之一是否可以成为“驱动程序”,在我们没有file_id
一个或多个查询返回的给定行的情况下。(例如,可能有来自 的行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 运算符将删除所有重复项)
要获得指定的结果集,我们可以使用该查询以及其他三个原始查询的“左连接”。查询的大纲将是:
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
值集的查询的替代(如上所示)。、和分别代表 sess、file_charges 和 file_payments 上的三个原始查询s
。c
p
如果任何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
(这个查询的解释不会很漂亮,有四个派生表。在非常大的集合上,性能可能很糟糕。但返回的结果集应该符合规范。)
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