为什么这个额外的WHERE子句不会返回我期望的内容?

时间:2012-07-15 03:00:10

标签: mysql group-by inner-join

我有2个数据库表,一个是仅包含未来日期的日历,另一个是具有库存分配的日历,其中包含数量,日期和产品ID。

总体而言,我需要一张表格,其中显示日期列表,其中任何库存分配数量在每个日期旁边分组为单个总计。

这是仅包含7月日期的日历:

CREATE TABLE `calendar` (
    `datefield` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

LOCK TABLES `calendar` WRITE; 

INSERT INTO `calendar` (`datefield`) VALUES 
('2012-07-01'),('2012-07-02'),('2012-07-03'),('2012-07-04'),('2012-07-05'),
('2012-07-06'),('2012-07-07'),('2012-07-08'),('2012-07-09'),('2012-07-10'),
('2012-07-11'),('2012-07-12'),('2012-07-13'),('2012-07-14'),('2012-07-15'),
('2012-07-16'),('2012-07-17'),('2012-07-18'),('2012-07-19'),('2012-07-20'), 
('2012-07-21'),('2012-07-22'),('2012-07-23'),('2012-07-24'),('2012-07-25'),
('2012-07-26'),('2012-07-27'),('2012-07-28'),('2012-07-29'),('2012-07-30'),
('2012-07-31'); 

UNLOCK TABLES;

这是股票分配表:

CREATE TABLE `stock_allocation` ( 
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `product_ID` int(11) NOT NULL,
    `date` date NOT NULL,
    `quantity` int(11) NOT NULL,
    PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

LOCK TABLES `stock_allocation` WRITE; 

INSERT INTO `stock_allocation` (`ID`, `product_ID`, `date`, `quantity`) VALUES
(1,3,'2012-07-30',50),
(2,3,'2012-07-26',40),
(3,3,'2012-07-26',100), 
(4,3,'2012-07-02',200),
(5,3,'2012-07-01',134); 

UNLOCK TABLES; 

我运行的查询给了我最接近我需要的信息:

SELECT 
    calendar.datefield AS date_allocation,
    IFNULL(SUM(stock_allocation.quantity),0) AS total_allocation 
FROM 
    stock_allocation 
RIGHT JOIN 
    calendar ON DATE(stock_allocation.date) = calendar.datefield 
WHERE 
    calendar.datefield >= '2012-12-01' AND 
    calendar.datefield <='2012-12-31' 
GROUP BY 
    date_allocation

所以这给出了类似于我所需要的东西:

    +-----------------+------------------+
    | date_allocation | total_allocation |
    +-----------------+------------------+
    | 2012-07-01      |              134 |
    | 2012-07-02      |              200 |
    | 2012-07-03      |                0 |
    | 2012-07-04      |                0 |
    | 2012-07-05      |                0 |
    | 2012-07-06      |                0 |
    | 2012-07-07      |                0 |
     etc etc
    | 2012-07-22      |                0 |
    | 2012-07-23      |                0 |
    | 2012-07-24      |                0 |
    | 2012-07-25      |                0 |
    | 2012-07-26      |              140 |
    | 2012-07-27      |                0 |
    | 2012-07-28      |                0 |
    | 2012-07-29      |                0 |
    | 2012-07-30      |               50 |
    | 2012-07-31      |                0 |
    +-----------------+------------------+

但是我想在这个最后的WHERE子句中添加以进行查询:

SELECT 
    calendar.datefield AS date_allocation,
    IFNULL(SUM(stock_allocation.quantity),0) AS total_allocation 
FROM 
    stock_allocation 
RIGHT JOIN 
    calendar ON DATE(stock_allocation.date) = calendar.datefield 
WHERE 
    calendar.datefield >= '2012-07-01' AND 
    calendar.datefield <='2012-07-31' AND 
    stock_allocation.product_ID = '3' 
GROUP BY 
    date_allocation

但是这个输出会返回:

    +-----------------+------------------+
    | date_allocation | total_allocation |
    +-----------------+------------------+
    | 2012-07-26      |              140 |
    | 2012-07-30      |               50 |
    +-----------------+------------------+

我希望你能理解我的需要 - 考虑到包含的样本日期,我希望两个查询返回基本相同的东西,因为样本stock_allocation数据的productID始终为3.

4 个答案:

答案 0 :(得分:1)

与其他人一样,您需要将过滤条件更改为基于product_id字段而非ID字段。

但是,如果您仍希望显示所有日历日期而仅对product_id = 3行执行求和,则应将AND product_id = 3添加到LEFT JOIN子句而不是WHERE条款。这样,没有连接的日历行product_id = 3仍保留在最终结果集中而不是过滤掉(WHERE子句所做的):

SELECT 
    a.datefield AS date_allocation,
    IFNULL(SUM(b.quantity),0) AS total_allocation 
FROM
    calendar a
LEFT JOIN
    stock_allocation b 
    ON a.datefield = b.date AND
       b.product_id = 3
WHERE 
    a.datefield BETWEEN '2012-07-01' AND '2012-07-31'
GROUP BY 
    a.datefield

答案 1 :(得分:0)

AND stock_allocation.ID更改为AND stock_allocation.product_ID

答案 2 :(得分:0)

不应该是stock_allocation.product_ID = '3'而不是stock_allocation.ID = '3'。 stock_allocation.ID将始终是唯一的,您只有1个值为'3'的条目

答案 3 :(得分:0)

您的查询没有返回行的原因是WHERE子句正在从日历中删除所有那些没有来自stock_allocation的匹配行的行。 WHERE子句正在击败OUTER JOIN,使其像INNER JOIN一样工作。

您希望在ON子句中使用该谓词,而不是WHERE子句。

这将为您提供所有您想要的零日历日期。

像这样:

SELECT 
    calendar.datefield AS date_allocation,
    IFNULL(SUM(stock_allocation.quantity),0) AS total_allocation 
FROM 
    stock_allocation 
RIGHT JOIN 
    calendar 
ON 
    stock_allocation.date = calendar.datefield 
    AND stock_allocation.product_ID = '3' 
WHERE 
    calendar.datefield >= '2012-07-01' AND 
    calendar.datefield <='2012-07-31' AND 
GROUP BY 
    date_allocation

注意:您不需要围绕stock_allocation.date列的DATE()函数,该列的数据类型已经是DATE。