左连接3个表 - 无法正确

时间:2012-08-02 02:17:55

标签: mysql

我正在尝试使用where子句对3个表进行左连接,但我无法使其工作。

我的表是:

sale:
sale_id (int)
terminal_id (int)
zread_id (int)
... more fields about total amounts, dates times etc

sale_payment:
payment_id (int)
sale_id (int)
payment_type (enum: 'P','W','A')
method_id (int)
payment_amount (Decimal)

sale_writeoff_method:
method_id (int)
description (varchar)
display_order (int)

销售可以通过3种不同方式(因此是Enum)最终确定(支付)实物支付 - 现金,支票等,“注销”支付 - 股票以成本价格用完(即浪费,赠品等)或账户 - 客户信用等

在销售期结束时(一天结束),用户执行Z-Read,收集所有发生的交易并生成报告,然后用户必须平衡抽屉中的现金等。当我'在创建初始Z-Read对象时,我可以使用查询收集所需信息:

SELECT m.method_id, m.description, SUM(s.sale_total) as z_total, COUNT(s.sale_id) as total_sales
FROM sale_writeoff_method m
LEFT JOIN sale_payment p ON m.method_id = p.method_id
LEFT JOIN sale s ON s.sale_id = p.sale_id 
WHERE s.zread_id IS NULL 
AND (p.payment_type = 'W' OR p.payment_type IS NULL) 
AND (s.terminal_id = ? OR s.terminal_id IS NULL) 
GROUP BY p.payment_type, m.method_id 
ORDER BY m.display_order;

一旦所有内容均衡并最终确定,销售表中所有类型的所有已收集销售额都会被插入此对象所产生的zread_id标记。

现在我的问题是,当我需要在将来重新创建z-read对象时,例如,为了重新打印报告,我无法获得所有的method_id和描述 - 我的查询一直在使用的是:

SELECT m.method_id, m.description, SUM(s.sale_total) as z_total, COUNT(s.sale_id) as total_sales 
FROM sale_writeoff_method m 
LEFT JOIN sale_payment p ON m.method_id = p.method_id 
LEFT JOIN sale s ON s.sale_id = p.sale_id 
WHERE s.zread_id = 1 
AND (p.payment_type = 'W' OR p.payment_type IS NULL) 
GROUP BY p.payment_type, m.method_id 
ORDER BY m.display_order;

But it only displays methods that had sales attached for that Z-Read period. I can't use WHERE s.zread_id IS NULL because that will include all the sales that haven't been finalised yet.

任何建议都将不胜感激!

1 个答案:

答案 0 :(得分:2)

问题是左连接为没有找到匹配行的连接列值返回空值,但是您正在检查where子句中的那些列值,但where谓词是在所有行被连接之后执行,因此它们永远不会匹配,并且您的外连接会被沉没。

即,此示例查询:

select *
from table1 t1
left join table2 t2 on t2.fk = t1.id
where t2.col1 = 'x'

从不返回table2中没有相应行的任何行,因为col1将为null,并与{{1}进行比较} nullfalse除外。

要解决此问题,您需要将测试移到col1 is null子句中,以便在进行连接时进行的比较,如下所示:

ON

现在左连接仍会在匹配键时返回行,并应用额外的谓词来进一步细化匹配。


在您的情况下,您正在进行外部(即select * from table1 t1 left join table2 t2 on t2.fk = t1.id and t2.col1 = 'x' )加入left,但在where子句中测试sale_payment p,这将无效。

这是固定查询,在p.payment_type = 'W'子句中对左连接表进行测试:

ON

请注意,我还删除了SELECT m.method_id, m.description, SUM(s.sale_total) as z_total, COUNT(s.sale_id) as total_sales FROM sale_writeoff_method m LEFT JOIN sale_payment p ON m.method_id = p.method_id AND p.payment_type = 'W' LEFT JOIN sale s ON s.sale_id = p.sale_id AND s.terminal_id = ? GROUP BY m.method_id, m.description ORDER BY m.display_order; ,因为您尚未选择该列,我添加了group by p.payment_type分组,因为已选择

您可能需要微调查询,但希望这将非常接近