Соединение 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 < NOW()
а также 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();
Проблема с этим в том, что он возвращал только продукты с действительной скидкой. Продукты без скидок или истекших / будущих скидок не показаны.
Далее я попробовал:
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 и не должна быть включена в это утверждение. Любая помощь высоко ценится!
Решение
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()
Более эффективно и более «стандартный», чем подзадача.
Другие советы
Как насчет
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
Вы, наверное 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
Пункт.
Вот что именно Внешние соединения были изобретены для.
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
. Анкет Тем не менее, все еще хорошо помнить, что они являются внешними соединениями, а не обычными внутренними соединениями.