订单查看添加不应该存在的项目

时间:2016-03-21 23:12:37

标签: mysql

对于mySQL分配,我们将创建一个视图,其中包含2014-01-01和2014-03-28之间订购的数据库中的打印件的item_id,title,artist,unit_price和order_qty。

CREATE VIEW orders_v AS
  SELECT items.item_id, title, artist, unit_price,
  order_qty
  FROM items, orderline, orders
  WHERE items.item_id = orderline.item_id
  AND orderline.order_id = orders.order_id
  AND orders.order_date like '2014-01%'
  OR orders.order_date like '2014-02%'
  GROUP BY items.item_id;

但是,视图中的数据显示在从未订购过的商品中,我无法找到原因。

在我的测试中,应该只有四个订单落在所需的时间段内:order_id	 10,11和12。

order_id:  9, item_id: 100, order_qty: 3
order_id: 10, item_id: 450, order_qty: 6
order_id: 10, item_id: 600, order_qty: 8
order_id: 10, item_id: 200, order_qty: 4
order_id: 11, item_id: 700, order_qty: 2
order_id: 12, item_id: 300, order_qty: 4

但相反,它会显示不会被订购的商品,例如item_id:400,或者在时间范围之外订购的商品。

任何帮助或建议都将不胜感激。

我的代码可以找到here,如果查看和测试它会有所帮助。

3 个答案:

答案 0 :(得分:1)

您需要将以下部分放在括号中:

  ( orders.order_date like '2014-01%'
    OR orders.order_date like '2014-02%'
  )

这是因为AND优先于OR,因此如果没有括号,则表示所有先前条件必须为真,或者最后一条(单独)。这不是您的意图,因为您希望以前的条件始终为真。

其次,由于您按项目对结果进行分组,但不对订单数量求和,因此您只需获取匹配的第一条记录的订单数量。这可能不是你想要的。只需将sum()包裹在其周围:

select ... sum(order_qty)

尽管匹配日期与LIKE有效,但您应该考虑更改比较日期的方式,因为它不能维持更长时间,对于更精确的范围更难。相反,请使用BETWEEN,您可以将限制设置为当天:

orders.order_date between '2014-01-01' and '2014-02-28'

请参阅具有更正的this SQL fiddle。它返回此结果集:

+---------+---------------+------------------+------------+-----------+
| item_id |     title     |     artist       | unit_price | order_qty |
+---------+---------------+------------------+------------+-----------+
|   100   | Under the Sun | Donald Arley     |     46.8   |    3      |
|   200   | Dark Lady     | Keith Morris     |    120.99  |    4      |
|   300   | Happy Days    | Andrea Reid      |     78     |    3      |
|   450   | The Hunt      | Walter Alford    |     39.99  |    6      |
|   600   | Rainbow Row   | Judy Ford        |     46     |    8      |
|   700   | Skies Above   | Alexander Wilson |     98     |    6      |
+---------+---------------+------------------+------------+-----------+

答案 1 :(得分:1)

括号是你的朋友。 OR的优先级高于AND,因此您在2月份的所有订单上获得了笛卡尔积。您的视图应定义为

CREATE VIEW orders_v AS
  SELECT items.item_id, title, artist, unit_price, order_qty
    FROM items, orderline, orders
    WHERE items.item_id = orderline.item_id
      AND orderline.order_id = orders.order_id
      AND (orders.order_date like '2014-01%'
       OR orders.order_date like '2014-02%')
    GROUP BY items.item_id;

答案 2 :(得分:1)

有几种方法可以改善您的查询。首先是使用JOIN syntax将where连接与where子句分开。这使查询更容易阅读,并有助于发现问题。

SELECT items.item_id, title, artist, unit_price, order_qty
  FROM items
  JOIN orderline ON items.item_id = orderline.item_id
  JOIN orders    ON orderline.order_id = orders.order_id
  WHERE orders.order_date like '2014-01%'
     OR orders.order_date like '2014-02%'
  GROUP BY items.item_id

正如其他答案中所指出的,这可以解决您的问题,因为它不再是AND / OR优先问题。

其次是使用CHAR(10)存储日期的不幸选择。幸运的是,您使用的是ISO 8601格式,因此您可以轻松对其进行排序,但最好将它们存储为DATEDATETIME,以充分利用MySQL's date functions的全部范围和日期索引,并使用较少的存储空间。如果order_dateDATE,您可以使用BETWEEN编写查询。

SELECT items.item_id, title, artist, unit_price, order_qty
  FROM items
  JOIN orderline ON items.item_id = orderline.item_id
  JOIN orders    ON orderline.order_id = orders.order_id
  WHERE orders.order_date BETWEEN '2014-01-01' AND '2014-02-28'
  GROUP BY items.item_id