我有一个名为ORDERS
的表,其中包含产品和订购数量的列表:
ORDER N° | PRODUCT | QUANTITY
1 | BICYCLE | 10
2 | BICYCLE | 3
3 | CAR | 2
...
另一个名为COMPOSITION
的表以分层方式保存第一个表中产品的所有组件的列表。
PRODUCT | COMPONENT | FACTOR
BICYCLE | FRAME | 1
FRAME | ALUMINUM BARS | 12
BICYCLE | DRIVING UNIT | 1
DRIVING UNIT | SMALL GEAR | 1
DRIVING UNIT | BIG GEAR | 1
DRIVING UNIT | CHAIN | 1
DRIVING UNIT | PEDALS SET | 2
PEDALS SET | PEDALS | 1
PEDALS SET | SCREWS | 4
...
这意味着自行车由1个框架制成,而框架又由12个铝条制成。每辆自行车也由1个驱动单元组成,每个单元由1个小型和1个大齿轮,1个链条和2个踏板组成,每个踏板组由1个踏板和4个螺丝组成。
出于简化目的,提供的示例仅适用于自行车,但该表包含所有可用产品的组件,每个层次结构中的级别数因产品而异。
我有一个名为STOCK
的第三个表,其中包含上表中提到的每个组件的库存。
COMPONENT | STOCK
BICYCLE | 2
FRAME | 5
ALUMINUM BARS | 26
DRIVING UNIT | 7
...
PEDALS SET | 0
PEDALS | 5
SCREWS | 10
我想使用SQL查询来确定缺少每个组件的数量来完成订单。
计算示例:
Quantity ordered of bicycles 10 + 3 = 13
Missing quantity of bicycles = 13 - 2 (stock) = 11
Missing quantity of frames = 11 * 1 (1 per bicycle) - 5 (stock) = 6
...
Missing quantity of driving units = 11 * 1 (1 per bicycle) - 7 (stock) = 4
Missing quantity of pedals sets 4 * 2 (2 per driving unit) - 0 (stock) = 8
Missing quantity of pedals = 8 * 1 (1 per pedals set) - 5 (stock) = 3
Missing quantity of screws = 8 * 4 (4 per pedals set) - 10 (stock) = 22
...
所以决赛桌看起来像是:
COMPONENT | MISSING
FRAMES | 6
...
DRIVING UNIT | 4
PEDALS SET | 8
PEDALS | 3
SCREWS | 22
...
答案 0 :(得分:0)
Oracle安装程序:
CREATE TABLE composition ( PRODUCT, COMPONENT, FACTOR ) AS
SELECT 'BICYCLE', 'FRAME', 1 FROM DUAL UNION ALL
SELECT 'FRAME', 'ALUMINUM BARS', 12 FROM DUAL UNION ALL
SELECT 'BICYCLE', 'DRIVING UNIT', 1 FROM DUAL UNION ALL
SELECT 'DRIVING UNIT', 'SMALL GEAR', 1 FROM DUAL UNION ALL
SELECT 'DRIVING UNIT', 'BIG GEAR', 1 FROM DUAL UNION ALL
SELECT 'DRIVING UNIT', 'CHAIN', 1 FROM DUAL UNION ALL
SELECT 'DRIVING UNIT', 'PEDALS SET', 2 FROM DUAL UNION ALL
SELECT 'PEDALS SET', 'PEDALS', 1 FROM DUAL UNION ALL
SELECT 'PEDALS SET', 'SCREWS', 4 FROM DUAL;
CREATE TABLE orders ( ORDER_NO, PRODUCT, QUANTITY ) AS
SELECT 1, 'BICYCLE', 10 FROM DUAL UNION ALL
SELECT 2, 'BICYCLE', 3 FROM DUAL UNION ALL
SELECT 3, 'CAR', 2 FROM DUAL;
CREATE TABLE stock ( COMPONENT, STOCK ) AS
SELECT 'BICYCLE', 2 FROM DUAL UNION ALL
SELECT 'FRAME', 5 FROM DUAL UNION ALL
SELECT 'ALUMINUM BARS', 26 FROM DUAL UNION ALL
SELECT 'DRIVING UNIT', 7 FROM DUAL UNION ALL
SELECT 'PEDALS SET', 0 FROM DUAL UNION ALL
SELECT 'PEDALS', 5 FROM DUAL UNION ALL
SELECT 'SCREWS', 10 FROM DUAL;
CREATE OR REPLACE PACKAGE stock_pkg IS
TYPE composition_table IS TABLE OF COMPOSITION%ROWTYPE;
FUNCTION path(
root IN COMPOSITION.PRODUCT%TYPE,
leaf IN COMPOSITION.COMPONENT%TYPE
) RETURN composition_table PIPELINED;
FUNCTION calculateFactor(
root IN COMPOSITION.PRODUCT%TYPE,
stop_at IN COMPOSITION.PRODUCT%TYPE,
leaf IN COMPOSITION.COMPONENT%TYPE
) RETURN NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY stock_pkg
IS
FUNCTION path(
root IN COMPOSITION.PRODUCT%TYPE,
leaf IN COMPOSITION.COMPONENT%TYPE
) RETURN composition_table PIPELINED
IS
CURSOR cur IS
SELECT up.product,
up.component,
up.factor
FROM (
SELECT c.*, ROWID AS rid
FROM composition c
START WITH product = root
CONNECT BY product = PRIOR component
) up
INNER JOIN
(
SELECT ROWID AS rid
FROM composition
START WITH component = leaf
CONNECT BY PRIOR product = component
) down
ON ( up.RID = down.RID );
r_composition COMPOSITION%ROWTYPE;
BEGIN
OPEN cur;
LOOP
FETCH cur INTO r_composition;
EXIT WHEN cur%NOTFOUND;
PIPE ROW( r_composition );
END LOOP;
CLOSE cur;
EXCEPTION
WHEN NO_DATA_NEEDED THEN
CLOSE cur;
RAISE;
END;
FUNCTION calculateFactor(
root IN COMPOSITION.PRODUCT%TYPE,
stop_at IN COMPOSITION.PRODUCT%TYPE,
leaf IN COMPOSITION.COMPONENT%TYPE
) RETURN NUMBER
IS
factor COMPOSITION.FACTOR%TYPE;
BEGIN
SELECT COALESCE( ROUND(EXP(SUM(LN(factor)))), 1 )
INTO factor
FROM TABLE( stock_pkg.path( root, leaf ) )
START WITH component = leaf AND component != stop_at
CONNECT BY PRIOR product = component AND component != stop_at;
RETURN factor;
END;
END;
/
<强>查询强>:
WITH comp AS (
SELECT CONNECT_BY_ROOT( product ) AS root,
component,
stock_pkg.calculateFactor(
root => CONNECT_BY_ROOT( product ),
stop_at => CONNECT_BY_ROOT( product ),
leaf => component
) AS total_factor
FROM composition c
START WITH product IN ( SELECT product FROM orders )
CONNECT BY PRIOR component = product
UNION ALL
SELECT DISTINCT
product,
product,
1
FROM orders
)
,multipliers AS (
SELECT root,
COALESCE( p.product, c.component ) AS product,
c.component,
c.total_factor,
stock_pkg.calculateFactor( c.root, p.product, c.component ) AS multiplier
FROM comp c,
TABLE( stock_pkg.path( c.root, c.component ) ) (+) p
)
,aggregated_stock AS (
SELECT root,
component,
SUM( factored_stock ) AS aggregated_stock
FROM (
SELECT m.root,
m.component,
s.stock * multiplier AS factored_stock
FROM multipliers m
INNER JOIN
stock s
ON ( m.product = s.component )
UNION ALL
SELECT c.root,
c.component,
s.stock
FROM comp c
INNER JOIN
stock s
ON ( c.component = s.component )
WHERE c.root != c.component
)
GROUP BY root, component
)
,total_orders AS (
SELECT product,
SUM( quantity ) AS quantity
FROM orders
GROUP BY product
)
,required_stock AS (
SELECT c.component,
SUM( c.total_factor * o.quantity ) AS total_quantity
FROM comp c
INNER JOIN
total_orders o
ON ( c.root = o.product )
GROUP BY c.component
)
SELECT r.component,
r.total_quantity - COALESCE( a.aggregated_stock, 0 ) AS missing
FROM required_stock r
LEFT OUTER JOIN
aggregated_stock a
ON ( r.component = a.component );
<强>输出强>:
COMPONENT MISSING
------------- ----------
BIG GEAR 4
CHAIN 4
PEDALS SET 8
PEDALS 3
SMALL GEAR 4
ALUMINUM BARS 46
FRAME 6
BICYCLE 11
SCREWS 22
DRIVING UNIT 4
CAR 2