2016-08-01 8 views
0

SQL beginner here。SQLクエリで注文を分割する

私の問題は、私はエクセルでそれを説明しようと説明するのちょっと難しいですので:

enter image description here

が一定の重量をお届け異なるサプライヤー数といくつかのサプライヤー、それぞれがあります。 トラックはちょうど24トンしか運搬できないので、 という表を持っています。 30トンというのは、24トンと6トンの2つの異なる注文を意味します。

SQLクエリでこの問題を解決する方法はありますか?

ありがとうございました!再帰的な因数分解サブクエリを使用して

+0

は、あなただけのTON_WEIGHTを行い、計算を持っていないでしょうが、/24、それをテーブルの1列に格納しますか?なぜあなたは1台のトラックに24台と6台必要があるのか​​を知る必要があります。代わりに1.25台が保管され、この注文には1台と0.25台のトラックが必要です。すでに1台のトラックはフル24、0.25台のトラックは6台を意味するでしょうか? –

+0

SELECT Tons/30 AS TrucksはTABLENAMEから必要です;これにより結果が得られます。この結果をテーブルに入れることもできます。テーブルにこの情報が必要な場合は、テーブルに列を追加する別の理由もあります。何度も何度もやりたいとは思わないが、この場合は単純な分割がうまくいく。 –

+0

また、44.6のように1つの数字として、この注文は45台のトラックを必要とするため、これが読み取られます。 44が満員になり、次のトラックが6位になります。また、この数値を使用して44.6として合計費用を計算すると、1台のトラックにつき15ドルと言うことができます.44.6 * 15、別の簡単な計算とクエリ –

答えて

1

あなたは(あなたが11gR2の以上にしていると仮定)recursive subquery factoringを使用することができます。

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 

アンカー部材が元の重量、または24の場合を取得それはそれよりも高く、the least() functionを使用しています - これはトラックナンバー1のものです。残っているものを取り除きます(これは問題ではないため、ここではマイナスの可能性があります)。再帰メンバは、ゼロよりも大きい場合は、前のレベルからの残りの計算を繰り返します。

+0

ご協力ありがとうございます!私のテーブルが2つの行supplier_numbersとorder_weight(私の例で示すように)で構成され、テーブルの名前が "t"であると仮定すると、このメソッドは機能しますか?残念ながら私は今すぐテストすることができませんが、明日は動作するかどうかを報告します! – lexcro

+0

はい、サンプルデータを供給するために 't'というCTEを使用しましたが、それは私が示した出力を生成しました。 't'をあなたの実際のテーブル名に変更します。 –

+0

ありがとうございます。たとえば、サプライヤの郵便番号のような行を追加したいとしたら、どうすればいいですか?私はかなり新しいSQLのため、私はエラーを取得せずにコードを変更することはできませんでした。 – lexcro

1

ソリューション:

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 
1

これは数値表で行うことができます。私はあなたが持っていると仮定しましょう1:

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; 

ここにあなたのテーブルが十分に大きければ、数字テーブルを生成する一つの簡単な方法です:

with numbers as (
     select rownum as n 
     from t 
    ) 
+0

t.tonsが24で割り切れる場合、これは機能しません。例:t.tons = 24。結合条件によって、nが1に制限されます。これは正しいです。しかし、CASE式は24ではなく0を返します(1 * 24は<24)。 (これは簡単に修正できますが、最初の<を<=に変更しますが、サイトのトップエキスパートの方がより良いと期待しています...) – mathguy

+0

@mathguy。 。 。私はむしろあなたのコメントが恋しいです。トン数が24の場合は、1つの行しか作成されません。あなたのコメントは理由を説明します。 –

+0

正しいですが、1つの行のみが生成されますが、転送されたウェイト(スプレッドシートの右側にOPが「オーダーウェイト」と呼ぶもの)は24にする必要があります。 mod(24,24)= 0、24ではなく – mathguy

関連する問題