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

Posted

技术标签:

【中文标题】即使右表与 where 不匹配也显示左表的 SQL 连接【英文标题】:SQL join that displays left table even if right table doesn't match where 【发布时间】:2009-12-10 22:11:59 【问题描述】:

我有 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;

如果有带有sDate < NOW()eDate > NOW() 的折扣条目,我正在尝试为每个产品和NULL 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;

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

在任何时候检查是否只有 1 个折扣有效是在 php 中完成的,不需要包含在此语句中。非常感谢任何帮助!

【问题讨论】:

什么数据库系统?什么版本?? 【参考方案1】:
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()

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

【讨论】:

这与接受的答案相同,但我之前发布过这个;)【参考方案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

【讨论】:

哈哈!!完成工作的3种方法,我想不出一个!谢谢大佬!【参考方案3】:

您可能希望子查询返回过滤后的discount 版本,然后您可以使用product 离开连接。

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 子句应用于一个表,你将它应用到子查询中的那个表,然后加入结果数据集,而不是先加入表然后过滤。)

【讨论】:

【参考方案4】:

这正是 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。但是,最好记住它们是外连接,而不是通常的内连接。

【讨论】:

以上是关于即使右表与 where 不匹配也显示左表的 SQL 连接的主要内容,如果未能解决你的问题,请参考以下文章

表连接中的驱动表与被驱动表

MySql 之 left join 查询结果

两个表进行左连接(LEFT JOIN ) 如何只显示右表中为空值的记录行,左表与右表存在关联的记录不显示。

SQL JOIN 数据库表关联关系

求SQL语句里面join的用法,求例子及讲解。

SQL-JOIN链接