连接表并用指定值替换空值

时间:2012-01-16 07:26:22

标签: php mysql sql pdo

我正在尝试制作一个可打印的页面,其中包含指定制造商的所有销售,列出指定日期之间的所有产品。如果没有任何销售,则应显示0。

表格

// Manufacturer table
// mid, manufacturer
// Products table
// pid, product, ref_manufacturer_id
// Orders table
// oid, orderPrice, orderDateTime, ref_product_id

有效的查询(没有日期限制)

SELECT prod.product, COALESCE(COUNT(pord.oid),0) AS orderCount,
COALESCE(SUM(pord.orderPrice),0) AS orderSum
FROM product_manufacturer AS manu
JOIN product_list AS prod ON prod.ref_manufacturer_id = manu.mid
LEFT JOIN product_orders AS pord ON pord.ref_product_id = prod.pid
WHERE manu.mid = :manu_id
GROUP BY prod.product;

但是只要我加入WHERE-syntax这个

WHERE manu.mid = :manu_id AND DATE(pord.orderDateTime) BETWEEN :orders_start AND :orders_end

我在连接和验证manu_id是int并且orders_start / end转换为MySQL日期格式时使用PHP PDO。

但我试图解决的问题是,导致问题的原因是,当我添加日期限制时,每个未订购的产品都不会显示在输出中?

创建表的SQL

CREATE TABLE product_list (
  pid bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  product varchar(255) NOT NULL,
  ref_manufacturer_id bigint(20) unsigned NOT NULL,
  PRIMARY KEY (pid),
  KEY ref_manufacturer_id (ref_manufacturer_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE product_manufacturer (
  mid bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  manufacturer varchar(255) NOT NULL,
  PRIMARY KEY (mid),
  UNIQUE KEY manufacturer (manufacturer)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE product_orders (
  oid bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  orderPrice float(10,2) NOT NULL,
  orderDatetime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  red_product_id bigint(20) unsigned NOT NULL,
  PRIMARY KEY (oid),
  KEY red_product_id (red_product_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

4 个答案:

答案 0 :(得分:2)

尝试:

SELECT p.product, 
    COALESCE(o.orderCount, 0) as orderCount, 
    COALESCE(o.orderSum,0) AS orderSum
FROM product_manufacturer AS m
JOIN product_list AS p ON p.ref_manufacturer_id = m.mid
LEFT JOIN (
    SELECT ref_product_id as pid, COUNT(oid) AS orderCount, SUM(orderPrice) AS orderSum
    FROM product_orders
    WHERE DATE(orderDateTime) BETWEEN :orders_start AND :orders_end
    GROUP BY ref_product_id
) AS o ON p.pid = o.pid
WHERE m.mid = :manu_id

修改:在ypercube评论后更正。

答案 1 :(得分:2)

您需要将orderDateTime条件移动到join子句而不是where子句:

SELECT prod.product, COALESCE(COUNT(pord.oid),0) AS orderCount,
       COALESCE(SUM(pord.orderPrice),0) AS orderSum
FROM product_manufacturer AS manu
JOIN product_list AS prod ON prod.ref_manufacturer_id = manu.mid
LEFT JOIN product_orders AS pord 
          ON pord.ref_product_id = prod.pid
          AND DATE(pord.orderDateTime) BETWEEN :orders_start AND :orders_end
WHERE manu.mid = :manu_id
GROUP BY prod.product;

它在WHERE子句中不起作用的原因是由于外连接返回的NULL值。如果产品的product_orders中没有行,则外部联接会为日期字段orderDateTime返回NULL,并且该行将被过滤掉,因为NULL不等于任何东西。

答案 2 :(得分:0)

在where子句上尝试这个。

WHERE manu.mid = :manu_id AND (DATE(pord.orderDateTime) BETWEEN :orders_start AND :orders_end)

它可能正在读取第二个AND函数作为另一个where子句,该语句应该返回true。只是预感。如果这样做,请告诉我。

答案 3 :(得分:0)

我不知道您的特定系统是如何工作的,但可能orderDateTime未设置(即NULL或其他内容),直到该产品被订购为止。您可以尝试:

WHERE manu.mid = :manu_id AND ((DATE(pord.orderDateTime) BETWEEN :orders_start AND :orders_end) OR pord.orderDateTime=NULL)

如果不是这种情况,你能举例说明你想要的东西没有显示的orderDateTime值吗?