即使右表与位置不匹配,SQL 连接也会显示左表
我有 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;
我试图为每个产品获取恰好 1 行的结果,以及 NULL
dPrice 或 dPrice(如果存在 sDate
sDate
sDate
sDate < )的折扣条目。 NOW() 和 eDate >现在()。
我尝试过:
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 个折扣处于活动状态是在 PHP 中完成的,不需要包含在此语句中。非常感谢任何帮助!
I have 2 tables, defined as such:
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;
I am trying to get a result of exactly 1 row for every product and a NULL
dPrice or the dPrice if there's a discount entry with sDate < NOW()
and eDate > NOW()
.
I tried:
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();
The problem with this is it returned only products with a valid discount. Products with no discount or expired / future discounts are not shown.
Next I tried:
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;
This came 1 step closer to my desired result, where it listed products with valid discounts and products with no discounts, but I'm still missing the products with expired / future discounts defined.
Checking that only 1 discount is active at any time is done in PHP and need not be included in this statement. Any help is much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
比子查询更高效、更“标准”。
More efficient and more "standard" than a subquery.
怎么样
What about
您可能希望子查询返回
discount
的过滤版本,然后您可以将其与product
左连接。(这里的 SQL 语法可能有一个轻微的错误,但您明白了:由于您只想将
WHERE
子句应用于一个表,因此您可以在子查询中将其应用于该表,然后连接结果数据集,而不是先连接表然后过滤。)You probably want a subquery to return a filtered version of
discount
that you can then left join withproduct
.(There may be a slight error in the SQL syntax here, but you get the idea: since you only want the
WHERE
clause to apply to one table, you apply it to that table in a subquery and then join the result data set, instead of joining the tables first and then filtering.)这正是 外连接 的发明目的。
从产品 p 中选择 p.*,d.dPrice 在 p.pid=d.pid 上左外连接折扣 d 并在 d.sDate 和 d.eDate 之间使用 now()
您可以使用缩写
左连接
而不是完整的左外连接
。然而,最好记住它们是外连接而不是通常的内连接。That's exactly what Outer Joins have been invented for.
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
You can use abbreviation
left join
instead of fullleft outer join
. However, it's still good to remember that they are outer joins as opposed to usual inner joins.