2013-06-11 43 views
3

我一直在努力与查询,我不知道它是否可能在纯sql或需要由php支持。多个日期范围股票超订查询

基本上我想生成一个订单报告,列出系统中超额预订的产品。

表结构:

订单

id int 
bookingStart DATETIME 
bookingEnd DATETIME 

ORDER_LINES

id int 
qty int 
product_id int 
booking_id int 

产品

id int 
stock int 

一个订单可以包含多行具有相同的产品。因此,订单上的每个产品都需要有一个SUM。有没有人有任何建议,以完成这个最好的方式?

我曾尝试与子查询一个特定的时间间隔循环,但它并没有考虑到不同的预订和我在这里有点卡住了,如果能有一个单一的查询来完成的重叠:

SELECT (SELECT SUM(lin2.qty) FROM booking_lines lin2,orders b2 
         WHERE 
         lin2.product_id=e.id AND 
         b2.id=lin2.booking_id AND       (
         (b2.bookingStart BETWEEN b1.bookingStart AND b1.bookingEnd) OR 
         (b2.bookingEnd BETWEEN b1.bookingStart AND b1.bookingEnd) OR 
         (b2.bookingStart < b1.bookingStart AND b2.bookingEnd >  b1.bookingEnd)       
         ) as booked SUM(lin1.qty) 
       FROM orders b1 
       LEFT JOIN order_lines lin1 ON b1.id=lin1.booking_id 
       LEFT JOIN products e ON e.id=lin1.product_id 

       (
        (b1.bookingStart BETWEEN '$s' AND '$e') OR 
        (b1.bookingEnd BETWEEN '$s' AND '$e') OR 
        (b1.bookingStart < '$s' AND b1.bookingEnd > '$e') 
     ) 
     GROUP BY b1.id,lin1.product_id 

问题 如果我们有产品x与股票10。

订单1已经预订了3乘积x 订单2已预订5乘积x 订单3已预订8产品下面X

线条表示预约的时间跨度

__ _ ___订单1 x:3_ __ _
              _ __订单2×:5_ __ _ _
_ __ _ __ _ ___订单3 x:8_ __ _ __
                                                                                        __为了4×2_

因此,它仅在3个数量级重叠的产品X实际上是超额预定,有什么我无法弄清楚是如何创建一个查询能够检测到。

+4

欢迎来到StackOverflow!请发布样本数据,基于它的期望输出,以及迄今为止所尝试的内容,以便我们看到您的努力。 – peterm

+0

在您的查询中,您有一个名为'booking_lines'的表的'LEFT JOIN'。你是指'order_lines'还是完全不同的表? – tftd

+0

是的,它的order_lines – sbdd

回答

1

我没有的MySQL实例来进行测试,但你有没有尝试过这样的事情:

select p.id, p.stock, t.bookedQty 
from products as p 
    inner join (
      select ol.product_id, sum(ol.qty) as bookedQty 
      from order_lines as ol 
       inner join orders as o on ol.booking_id = o.id 
      where o.bookingStart between '2013-06-10' and '2013-06-11' 
        and t.bookedQty > p.stock 
      group by ol.product_id) as t 

- 见注释1 -

我用SqlFiddle模式从tftd的答案在下面(谢谢)。这应该生成每天有超量预定在未来100,数量吃到黄牌,并在股票数量:

SELECT 
     date, 
     p.product_id, 
     sum(ol.qty) AS total_booked, 
     p.stock AS available 
FROM (
     SELECT c.date 
     FROM 
      (SELECT curdate() + interval (a.a + (10 * b.a)) DAY AS date 
      FROM 
      (SELECT 0 AS a 
       UNION ALL SELECT 1 
       UNION ALL SELECT 2 
       UNION ALL SELECT 3 
       UNION ALL SELECT 4 
       UNION ALL SELECT 5 
       UNION ALL SELECT 6 
       UNION ALL SELECT 7 
       UNION ALL SELECT 8 
       UNION ALL SELECT 9) AS a CROSS 
      JOIN 
      (SELECT 0 AS a 
       UNION ALL SELECT 1 
       UNION ALL SELECT 2 
       UNION ALL SELECT 3 
       UNION ALL SELECT 4 
       UNION ALL SELECT 5 
       UNION ALL SELECT 6 
       UNION ALL SELECT 7 
       UNION ALL SELECT 8 
       UNION ALL SELECT 9) AS b 
     ) AS c 
     WHERE c.date >= curdate() AND c.date < DATE_ADD(curdate(), INTERVAL 100 DAY) 
    ) AS gendates 
    INNER JOIN orders AS o ON o.bookingStart <= gendates.date AND o.bookingEnd > gendates.date 
    INNER JOIN order_lines AS ol ON o.order_id = ol.order_id 
    INNER JOIN products AS p ON ol.product_id = p.product_id 
GROUP BY gendates.date, p.product_id, p.stock 
HAVING total_booked > p.stock 

http://sqlfiddle.com/#!2/a5061e/25

Date generation link

+0

我沿着这些线路尝试了一些东西,但它没有考虑到重叠。我已经用更多的细节更新了这个问题。 – sbdd

+0

它与我想要的非常接近,除了bookingStart和bookingEnd是日期时间,所以我需要找到发生超量预订的特定间隔。 – sbdd

1

表结构

CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY, 
    name  VARCHAR(255), 
    stock  INT 
) ENGINE=InnoDB; 

CREATE TABLE orders (
    order_id  INT AUTO_INCREMENT PRIMARY KEY, 
    bookingStart DATETIME, 
    bookingEnd DATETIME 
) ENGINE=InnoDB; 


CREATE TABLE order_lines (
    line_id  INT AUTO_INCREMENT PRIMARY KEY, 
    order_id  INT, 
    product_id INT, 
    qty   INT NOT NULL DEFAULT 0, 
    CONSTRAINT FOREIGN KEY(order_id) REFERENCES orders(order_id) ON DELETE RESTRICT, 
    CONSTRAINT FOREIGN KEY(product_id) REFERENCES products(product_id) ON DELETE RESTRICT 
) ENGINE=InnoDB; 


INSERT INTO products(name, stock) VALUES('Product 1', 8); 
INSERT INTO products(name, stock) VALUES('Product 2', 14); 
INSERT INTO products(name, stock) VALUES('Product 3', 25); 

INSERT INTO orders(bookingStart,bookingEnd) VALUES(NOW(), (NOW() + INTERVAL 2 HOUR)); 
INSERT INTO orders(bookingStart,bookingEnd) VALUES(NOW(), (NOW() + INTERVAL 3 HOUR)); 
INSERT INTO orders(bookingStart,bookingEnd) VALUES(NOW(), (NOW() + INTERVAL 4 HOUR)); 

INSERT INTO order_lines(order_id, product_id, qty) VALUES(1, 1, 2); 
INSERT INTO order_lines(order_id, product_id, qty) VALUES(1, 1, 8); 
INSERT INTO order_lines(order_id, product_id, qty) VALUES(2, 2, 5); 
INSERT INTO order_lines(order_id, product_id, qty) VALUES(2, 2, 10); 
INSERT INTO order_lines(order_id, product_id, qty) VALUES(3, 3, 2); 
INSERT INTO order_lines(order_id, product_id, qty) VALUES(3, 3, 8); 
INSERT INTO order_lines(order_id, product_id, qty) VALUES(3, 3, 10); 

要获得超额预定产品:

SELECT 
    products.*, 
    SUM(order_lines.qty) as sum_qty 
FROM products 
LEFT JOIN order_lines ON order_lines.product_id = products.product_id 
LEFT JOIN orders ON orders.order_id = order_lines.order_id 
WHERE orders.bookingStart >= '2013-06-12' 
AND orders.bookingEnd <= '2013-06-14' 
GROUP BY order_lines.order_id, order_lines.product_id 
HAVING sum_qty > products.stock 

将返回Product 1Product 2,因为在order_linesqty总和大于products.stock大(这可能是该产品的可用数量?)。

SqlFiddle

+0

是的,但它需要考虑时间间隔,因为它是一个出租产品。所以它只有在特定时间间隔内超额预订时,问题是可能有多个指令跨越相同的时间间隔,因此需要考虑时间间隔来查找最大数量。 – sbdd

+0

那么只需在查询中的GROUP BY之前添加一个'WHERE'子句,它就会对它们进行过滤。我没有添加它,因为我只有3条记录。 – tftd

+0

我已经用更好的解释更新了这个问题。 – sbdd