1

我正在尝试使用 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 种不同的方式完成(支付)(因此是枚举)实物支付 - 现金、支票等,“注销”支付 - 库存以成本价(即浪费、赠品等)或账户 -客户信用等

在销售期结束时(一天结束),用户进行 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 对象时,例如重新打印报告,我无法显示所有的方法 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.

任何建议将不胜感激!

4

1 回答 1

2

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

即,这个示例查询:

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

永远不会返回任何在 中没有对应行的行table2,因为col1will benull和与nullare 的比较总是false,除了col1 is null.

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

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

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


在您的情况下,您正在对 进行外部(即left)连接sale_payment p,但p.payment_type = 'W'在 where 子句中进行测试,这是行不通的。

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,因为您尚未选择该列,并且我添加了 group by m.description,因为您选择了该列。

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

于 2012-08-02T02:58:08.390 回答