即使右表与where匹配,也会显示左表的SQL连接

时间:2009-12-10 22:12:00

标签: sql mysql select join left-join

我有2个表,定义如下:

CREATE TABLE `product` (
`pid` SMALLINT( 5 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR( 50 ) NOT NULL,
`description` TEXT,
`qty` SMALLINT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
`category` ENUM( '1', '2', '3', '4', '5', '6', '7', '8' ) NOT NULL DEFAULT '1',
`price` DECIMAL( 7, 2 ) UNSIGNED NOT NULL
) ENGINE = InnoDB;

CREATE TABLE `discount` (
`did` SMALLINT( 5 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`pid` SMALLINT( 5 ) UNSIGNED NOT NULL,
`sDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`eDate` DATETIME NOT NULL,
`dPrice` DECIMAL( 7, 2 ) UNSIGNED NOT NULL,
FOREIGN KEY ( `pid` ) REFERENCES `product`(`pid`)
    ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB;

如果有NULLsDate < NOW()的折扣条目,我试图为每个产品和eDate > NOW() dPrice或dPrice获得恰好1行的结果。

我试过了:

select p.pid, name, price, dPrice, qty
from product p left join discount d
on p.pid = d.pid
where d.sDate<now() and d.eDate>now();

这个问题是它只返回有效折扣的产品。没有折扣或过期/未来折扣的产品不会显示。

接下来我尝试了:

select p.pid, name, price, dPrice, qty
from product p left join discount d
on p.pid = d.pid
where (d.sDate<now() and d.eDate>now()) or dPrice is null;

这比我想要的结果更接近一步,它列出了有效折扣的产品和没有折扣的产品,但我仍然缺少定义了过期/未来折扣的产品。

在PHP中检查任何时候只有1个折扣处于活动状态,不需要包含在此声明中。非常感谢任何帮助!

4 个答案:

答案 0 :(得分:4)

select p.pid, name, price, dPrice, qty
from product p 

left join discount d on p.pid = d.pid and d.sDate<now() and d.eDate>now()

比子查询更高效,更“标准”。

答案 1 :(得分:2)

怎么样?
SELECT p.name, d.dPrice
FROM   product p LEFT JOIN discount d
ON     p.pid = d.pid AND now() BETWEEN d.sDate AND d.eDate

答案 2 :(得分:1)

您可能希望子查询返回discount的过滤版本,然后您可以使用product加入。{/ p>

select p.pid, name, price, dPrice, qty
from product p left join
(select * from discount where sDate<now() and eDate>now()) d
on p.pid = d.pid;

(这里的SQL语法可能有轻微的错误,但你明白了:因为你只想将WHERE子句应用于一个表,所以你将它应用于子查询中的那个表然后加入结果数据集,而不是先加入表格然后过滤。)

答案 3 :(得分:0)

这正是Outer Joins所发明的。

select p.*,d.dPrice from product p left outer join discount d on p.pid=d.pid and now() between d.sDate and d.eDate

您可以使用缩写left join代替完整left outer join。但是,记住它们是外连接而不是通常的内连接仍然是好的。