Reputation: 3
SQL beginner here.
Since my problem is kinda hard to explain I will try to illustrate it with Excel:
There are some suppliers, each with a different supplier-number who deliver a certain weight. Since a truck can only transport exactly 24 tons I'd like to have table with the orders splitted by the value of 24. So 30 tons would mean 2 different orders one with 24 tons and one with 6 tons.
Is there any way you know of to solve this problem with a SQL query?
Thanks for any help!
Upvotes: 0
Views: 94
Reputation: 1269983
You can do this with a numbers table. Let me assume that you have one:
select t.*, n.n,
(case when n.n * 24 <= t.tons then 24
else mod(t.tons, 24)
end)
from t join
numbers n
on (n.n - 1) * 24 < t.tons;
Here is one simple way to generate a numbers table, if your table is large enough:
with numbers as (
select rownum as n
from t
)
Upvotes: 1
Reputation: 191295
You could use recursive subquery factoring (assuming you're on 11gR2 or higher):
with r (supplier_number, order_weight, truck_number, truck_weight, remaining_weight) as (
select supplier_number, order_weight, 1,
least(order_weight, 24), order_weight - 24
from t
union all
select supplier_number, order_weight, truck_number + 1,
least(remaining_weight, 24), remaining_weight - 24
from r
where remaining_weight > 0
)
select supplier_number, order_weight, truck_number, truck_weight
from r
order by supplier_number, truck_number;
SUPPLIER_NUMBER ORDER_WEIGHT TRUCK_NUMBER TRUCK_WEIGHT
--------------- ------------ ------------ ------------
1 10 1 10
2 25 1 24
2 25 2 1
3 88 1 24
3 88 2 24
3 88 3 24
3 88 4 16
The anchor member gets the original weight, or 24 if it's higher than that, using the least()
function - and that is what is in truck number 1; and also works out what's left (which may be negative here, since it doesn't matter). The recursive member repeats that calculation on the remainder from the previous level, if it is greater than zero.
Upvotes: 1
Reputation:
Solution using recursive factored subquery:
with
inputs ( supplier_number, order_weight ) as (
select 1, 10 from dual union all
select 2, 25 from dual union all
select 3, 88 from dual
),
r ( supplier_number, shipment_number, order_weight, weight_remaining ) as (
select supplier_number, 0, null, order_weight
from inputs
union all
select supplier_number, shipment_number + 1, least(24, weight_remaining),
greatest(0, weight_remaining - 24)
from r
where weight_remaining != 0
)
select supplier_number, shipment_number, order_weight
from r
where shipment_number > 0
order by supplier_number, shipment_number
;
SUPPLIER_NUMBER SHIPMENT_NUMBER ORDER_WEIGHT
--------------- --------------- ------------
1 1 10
2 1 24
2 2 1
3 1 24
3 2 24
3 3 24
3 4 16
Upvotes: 1