English 中文(简体)
SQL join that displays left table even if right table doesn t match where
原标题:

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!

最佳回答
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()

More efficient and more "standard" than a subquery.

问题回答

What about

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

You probably want a subquery to return a filtered version of discount that you can then left join with 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;

(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.)

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 full left outer join. However, it s still good to remember that they are outer joins as opposed to usual inner joins.





相关问题
SQL SubQuery getting particular column

I noticed that there were some threads with similar questions, and I did look through them but did not really get a convincing answer. Here s my question: The subquery below returns a Table with 3 ...

please can anyone check this while loop and if condition

<?php $con=mysql_connect("localhost","mts","mts"); if(!con) { die( unable to connect . mysql_error()); } mysql_select_db("mts",$con); /* date_default_timezone_set ("Asia/Calcutta"); $date = ...

php return a specific row from query

Is it possible in php to return a specific row of data from a mysql query? None of the fetch statements that I ve found return a 2 dimensional array to access specific rows. I want to be able to ...

Character Encodings in PHP and MySQL

Our website was developed with a meta tag set to... <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> This works fine for M-dashes and special quotes, etc. However, I ...

Pagination Strategies for Complex (slow) Datasets

What are some of the strategies being used for pagination of data sets that involve complex queries? count(*) takes ~1.5 sec so we don t want to hit the DB for every page view. Currently there are ~...

Averaging a total in mySQL

My table looks like person_id | car_id | miles ------------------------------ 1 | 1 | 100 1 | 2 | 200 2 | 3 | 1000 2 | 4 | 500 I need to ...

热门标签