Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Truy vấn FIFO SQL với nhóm theo

Tùy chọn 1

Đây có lẽ là một công việc cho PL / SQL. Bắt đầu với các kiểu dữ liệu để xuất:

CREATE TYPE supply_details_obj AS OBJECT(
  product_id  NUMBER,
  quantity    NUMBER,
  supplier_id NUMBER,
  customer_id NUMBER
);

CREATE TYPE supply_details_tab AS TABLE OF supply_details_obj;

Sau đó, chúng ta có thể xác định một hàm pipelined để đọc INVENTORY_ININVENTORY_OUT các bảng một hàng tại một thời điểm và hợp nhất hai hàng để giữ tổng số hàng tồn kho còn lại hoặc số lượng cần cung cấp đang hoạt động:

CREATE FUNCTION assign_suppliers_to_customers (
  i_product_id IN INVENTORY_IN.PRODUCT_ID%TYPE
)
RETURN supply_details_tab PIPELINED
IS
  v_supplier_id  INVENTORY_IN.SUPPLIER_ID%TYPE;
  v_customer_id  INVENTORY_OUT.CUSTOMER_ID%TYPE;
  v_quantity_in  INVENTORY_IN.IN_QUANTITY%TYPE   := NULL;
  v_quantity_out INVENTORY_OUT.OUT_QUANTITY%TYPE := NULL;
  v_cur_in       SYS_REFCURSOR;
  v_cur_out      SYS_REFCURSOR;
BEGIN
  OPEN v_cur_in FOR
    SELECT in_quantity, supplier_id
    FROM   INVENTORY_IN
    WHERE  product_id = i_product_id
    ORDER BY inv_timestamp;

  OPEN v_cur_out FOR
    SELECT out_quantity, customer_id
    FROM   INVENTORY_OUT
    WHERE  product_id = i_product_id
    ORDER BY inv_timestamp;

  LOOP
    IF v_quantity_in IS NULL THEN
      FETCH v_cur_in INTO v_quantity_in, v_supplier_id;
      IF v_cur_in%NOTFOUND THEN
        v_supplier_id := NULL;
      END IF;
    END IF;
    IF v_quantity_out IS NULL THEN
      FETCH v_cur_out INTO v_quantity_out, v_customer_id;
      IF v_cur_out%NOTFOUND THEN
        v_customer_id := NULL;
      END IF;
    END IF;

    EXIT WHEN v_cur_in%NOTFOUND AND v_cur_out%NOTFOUND;

    IF v_quantity_in > v_quantity_out THEN
      PIPE ROW(
        supply_details_obj(
          i_product_id,
          v_quantity_out,
          v_supplier_id,
          v_customer_id
        )
      );
      v_quantity_in  := v_quantity_in - v_quantity_out;
      v_quantity_out := NULL;
    ELSE
      PIPE ROW(
        supply_details_obj(
          i_product_id,
          v_quantity_in,
          v_supplier_id,
          v_customer_id
        )
      );
      v_quantity_out := v_quantity_out - v_quantity_in;
      v_quantity_in  := NULL;
    END IF;
  END LOOP;
END;
/

Sau đó, đối với dữ liệu mẫu:

CREATE TABLE INVENTORY_IN ( ID, INV_TIMESTAMP, PRODUCT_ID, IN_QUANTITY, SUPPLIER_ID ) AS
SELECT 0, TIMESTAMP '2021-03-09 00:00:00', 101,  20, 0 FROM DUAL UNION ALL
SELECT 1, TIMESTAMP '2021-03-10 01:00:00', 101, 100, 4 FROM DUAL UNION ALL
SELECT 2, TIMESTAMP '2021-03-11 02:00:00', 101,  50, 3 FROM DUAL UNION ALL
SELECT 3, TIMESTAMP '2021-03-14 01:00:00', 101,  10, 2 FROM DUAL;

CREATE TABLE INVENTORY_OUT ( ID, INV_TIMESTAMP, PRODUCT_ID, OUT_QUANTITY, CUSTOMER_ID ) AS
SELECT 1, TIMESTAMP '2021-03-10 02:00:00', 101, 30, 1 FROM DUAL UNION ALL
SELECT 2, TIMESTAMP '2021-03-11 01:00:00', 101, 40, 2 FROM DUAL UNION ALL
SELECT 3, TIMESTAMP '2021-03-12 01:00:00', 101, 80, 1 FROM DUAL;

Truy vấn:

SELECT product_id,
       supplier_id,
       customer_id,
       SUM( quantity ) AS quantity
FROM   TABLE( assign_suppliers_to_customers( 101 ) )
GROUP BY
       product_id,
       supplier_id,
       customer_id
ORDER BY
       MIN( inv_timestamp )

Kết quả đầu ra:

Tùy chọn 2

Một truy vấn SQL (rất) phức tạp:

WITH in_totals ( ID, INV_TIMESTAMP, PRODUCT_ID, IN_QUANTITY, SUPPLIER_ID, TOTAL_QUANTITY ) AS (
  SELECT i.*,
         SUM( in_quantity ) OVER ( PARTITION BY product_id ORDER BY inv_timestamp )
  FROM   inventory_in i
),
out_totals ( ID, INV_TIMESTAMP, PRODUCT_ID, OUT_QUANTITY, CUSTOMER_ID, TOTAL_QUANTITY ) AS (
  SELECT o.*,
         SUM( out_quantity ) OVER ( PARTITION BY product_id ORDER BY inv_timestamp )
  FROM   inventory_out o
),
split_totals ( product_id, inv_timestamp, supplier_id, customer_id, quantity ) AS (
  SELECT i.product_id,
         MIN( COALESCE( LEAST( i.inv_timestamp, o.inv_timestamp ), i.inv_timestamp ) )
           AS inv_timestamp,
         i.supplier_id,
         o.customer_id,
         SUM(
           COALESCE(
             LEAST(
               i.total_quantity - o.total_quantity + o.out_quantity,
               o.total_quantity - i.total_quantity + i.in_quantity,
               i.in_quantity,
               o.out_quantity
             ),
             0
           )
         )
  FROM   in_totals i
         LEFT OUTER JOIN
         out_totals o
         ON (   i.product_id = o.product_id
            AND i.total_quantity - i.in_quantity <= o.total_quantity
            AND i.total_quantity >= o.total_quantity - o.out_quantity )
  GROUP BY
         i.product_id,
         i.supplier_id,
         o.customer_id
  ORDER BY
         inv_timestamp
),
missing_totals ( product_id, inv_timestamp, supplier_id, customer_id, quantity ) AS (
  SELECT i.product_id,
         i.inv_timestamp,
         i.supplier_id,
         NULL,
         i.in_quantity - COALESCE( s.quantity, 0 )
  FROM   inventory_in i
         INNER JOIN (
           SELECT product_id,
                  supplier_id,
                  SUM( quantity ) AS quantity
           FROM   split_totals
           GROUP BY product_id, supplier_id
         ) s
         ON (   i.product_id = s.product_id
            AND i.supplier_id = s.supplier_id )
  ORDER BY i.inv_timestamp
)
SELECT product_id, supplier_id, customer_id, quantity
FROM   (
  SELECT product_id, inv_timestamp, supplier_id, customer_id, quantity
  FROM   split_totals
  WHERE  quantity > 0
  UNION ALL
  SELECT product_id, inv_timestamp, supplier_id, customer_id, quantity
  FROM   missing_totals
  WHERE  quantity > 0
  ORDER BY inv_timestamp
);

Đối với dữ liệu mẫu ở trên, kết quả đầu ra:

db <> fiddle tại đây



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chuỗi ngẫu nhiên SQL từ danh sách

  2. Oracle xử lý chuỗi trống là vấn đề NULL đối với lập trình viên Java / JPA

  3. Oracle để truy xuất bản ghi tối đa

  4. Cập nhật nhiều cột trong câu lệnh MERGE ORACLE

  5. Các ký tự đặc biệt của Oracle