简体   繁体   English

连接表并将空值替换为指定值

[英]Joining tables and replacing null values with specified values

I am trying to make a printable page, where there is all the sales of a specified manufacturer, listing all the products, between specified dates. 我正在尝试制作一个可打印的页面,其中包含指定制造商在指定日期之间的所有销售情况,列出所有产品。 If there has not been any sales, it should display 0. 如果没有任何销售,则应显示0。

The tables 桌子

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

And the query that works (without date limitation) 和有效的查询(无日期限制)

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;

But as soon as I add into the WHERE-syntax this 但是,一旦我添加到WHERE语法中,

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

I am using PHP PDO on connecting and verifying that the manu_id is int and the orders_start/end is converted to MySQL date format. 我在连接和验证manu_id为int且orders_start / end转换为MySQL日期格式时使用PHP PDO。

But the question I am trying to fidn out is, what is causing the problem, that when I add the date restriction, every product that was not ordered, is not displayed on the output? 但是我要查找的问题是,是什么原因导致问题,当我添加日期限制时,未订购的每个产品都不会显示在输出中?

SQL on creating the tables 创建表的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 ;

Try: 尝试:

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

Edit : Corrected after ypercube comment. 编辑 :ypercube评论后已更正。

What you need is to move the orderDateTime criteria to the join clause instead of where clause like: 您需要将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;

The reason it does not work within the WHERE clause is because of the NULL values returned from the outer join. 它在WHERE子句中不起作用的原因是由于从外部联接返回的NULL值。 When you do not have a row in product_orders fot a product, the outer join returns a NULL for the date field orderDateTime and that row will be filtered out because a NULL is not equal to anything. 当产品的product_orders没有行时,外部orderDateTime将为日期字段orderDateTime返回NULL,并且该行将被滤除,因为NULL不等于任何值。

try this on the where clause. 试试在where子句上。

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

It might be reading the second AND function as another where clause that the statement should return true. 它可能正在将第二个AND函数作为另一个where子句读取,该语句应返回true。 Just a hunch on that. 只是预感。 Let me know if this does the trick. 让我知道这是否有用。

I don't know how your specific system works, but it may be orderDateTime is not set (ie, NULL or something else) until that product gets ordered. 我不知道您的特定系统是如何工作的,但是可能要等到该产品被订购后,才能设置orderDateTime (即NULL或其他东西)。 You may want to try: 您可能要尝试:

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

If this is not the case, could you give an example of the orderDateTime value for something that is not showing up when you want it to? 如果不是这种情况,您是否可以举一些orderDateTime值的示例,以显示未希望显示的内容?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM