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

問題 在庫数が 10 の製品 x があるとします。

注文 1 は 3 個の製品を予約しました x 注文 2 は 5 個の製品を予約しました x 注文 3 は 8 個の製品を予約しました x

以下の行は、予約された期間を示します

__ _ ___注文 1 x:3 _ __ _
       _注文 2 x:5 _ __ _ _ __ _ _
_注文3 x:8 _ __ _ __注文4 x :2 _
                                            

そのため、3 つの注文が重複して製品 x が実際にオーバーブッキングされている場合にのみ、それを検出できるクエリを作成する方法がわかりません。

4

2 に答える 2

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 1れます。これは、 inProduct 2の合計が(おそらく製品の利用可能な数量はどちらでしょうか?)より大きいためです。qtyorder_linesproducts.stock

SqlFiddle

于 2013-06-11T22:01:26.267 に答える
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 を参照--

以下の tftd の回答の SqlFiddle スキーマを使用しました (感謝)。これは、オーバーブッキング、予約数量、および在庫数量を持つ次の 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

日付生成リンク

于 2013-06-11T21:38:22.090 に答える