2016-10-28 15 views
1

あるテーブルから別のテーブルにデータを転送しようとしています。しかし、私は何か余分なことをする必要があるプロセスでは、SQLやPL/SQLだけでこれを行うことが可能かどうか疑問に思っています。INSERT SELECTループ

 source     target 
-------------------  ------------------------ 
| id | name | qty |  | id | source_id | qty | 
-------------------  ------------------------ 
| 1 | test | 2 |  | 1 | 1   | 1 | 
-------------------  ------------------------ 
| 2 | ago | 1 |  | 2 | 1   | 1 |  
-------------------  ------------------------ 
          | 3 | 2   | 1 | 
          ----------------------- 

ここでソーステーブルの数量に基づいて、複数のレコードを挿入する必要があります。数量は任意の数にすることができます。ターゲット表のIDは自動的に増分されます。私はこの

INSERT INTO target (SELECT id, qty FROM source); 

を試してみました。しかし、これは数量ループの世話をしていません。

+0

私はあなたがそれを達成するためにPL/SQLを必要とするだろうと思うだろうが、私はまたあなたの主キーが新しいテーブルの上がどうなるか疑問に思います。 – topshot

+0

PL/SQLは、ターゲット表のIDも自動インクリメントです。私は質問で更新しました。 idが自動生成された場合 – nicholasnet

+0

だから、どのようにSOURCE_ID年代を順になりますことを確認する予定ですか?あなたが本当にちょうどSOURCE_IDと数量を生成する必要がある、と彼らはtarget' '内の任意の(新しい)IDを割り当てることができます - または無関係ということでしょうか? – mathguy

答えて

1

平野SQL:

with 
    inputs (id, qty) as (
     select 1, 2 from dual union all 
     select 2, 1 from dual union all 
     select 3, 5 from dual 
    ) 
-- end of test data; solution (SQL query) begins below this line 
select row_number() over (order by id) as id, id as source_id, 1 as qty 
from inputs 
connect by level <= qty 
     and prior id = id 
     and prior sys_guid() is not null 
; 

NOTE - idが自動的に生成されている場合、単にrow_number().... as id列をドロップ。残りは変わりません。

ID SOURCE_ID QTY 
-- --------- -- 
1   1 1 
2   1 1 
3   2 1 
4   3 1 
5   3 1 
6   3 1 
7   3 1 
8   3 1 
+0

右かっこの誤りがありません。 – nicholasnet

+0

申し訳ありませんが、私はそれを上書き - 修正されます。それはWITH句の最後にあります。 (私は解決策が始まる場所についてのコメントを追加したとき、私はそれを上書き) – mathguy

+0

をところで、あなたは 'INSERT'でこれを使用する必要がある場合、あなたはそのようにそれを記述する必要があります:' INSERT INTO .... SELECT ID、 1ソースから接続...'あなたはすでに' SOURCE'テーブルを持っているので、 'WITH'句はまったく必要なく、(' TARGET'テーブルのカラム名を持っている)カラム別名を使う必要はありません。新しい 'id'が自動生成されるなら、' ROW_NUMBER()OVER ... 'は必要ありません。 – mathguy

0
INSERT INTO TARGET(source_id, qty) 
    WITH 
    output 
    AS 
    (
     SELECT id, qty FROM source 
     UNION ALL 
     SELECT id, qty - 1 FROM source WHERE qty > 1 
    )  
    SELECT 
    id, count(*) as qty 
    FROM output 
    group by 
    id, quantity 
    ORDER BY 
    id 
+0

WITH句をINSERTと同様に使用することはできません。また、新しいID列を作成した場所が明確ではなく、実際には2つの列しか生成していません。 – mathguy

+0

著者はIDフィールドがコメント内の自動インクリメントカラムであり、SQLサーバーがCTEをサポートしていると述べています –

+0

ああ...私はそれを忘れました。 – mathguy

0

これは、SQLを使用して可能です。ソーステーブルから最大qtyに一致する行数を生成するにはCTEを使用し、行を生成するには非等価JOINを使用します。あなたが安全にコンスタンスに入れることができます注で1を評価

with gen_numbers(r) as (
select rownum r 
from dual 
connect by rownum <= (select max(qty) from src) -- our maximum limit of rows needed 
) 
select 
    row_number() over (order by src.id) as id, 
    src.id as source_id, 
    1 as qty 
from src 
join gen_numbers on src.qty <= gen_numbers.r; -- clone rows qty times 

:それはユニークなID (あなたがあなたのターゲット表でそれを持っている場合は、私の編集に以下を確認して)だ各行を割り当てることがrow_number分析関数を使用しますqtyの出力。


あなたのテストデータ:

create table src (id int, name varchar(255), qty int); 
insert into src (id, name, qty) 
    select 1, 'test', 2 from dual union all 
    select 2, 'ago', 1 from dual 
    ; 

結果:

ID SOURCE_ID QTY 
1 2   1 
2 2   1 
3 1   1 

編集:ターゲットid列が自動インクリメントされますので、必要のありませんrow_number。私は値を挿入する適切な順序を保証するためにORDER BY句を追加しました

with gen_numbers(r) as (
select rownum r 
from dual 
connect by rownum <= (select max(qty) from src) -- our maximum limit of rows needed 
) 
insert into target_table(source_id, qty) 
select 
    src.id as source_id, 
    1 as qty 
from src 
join gen_numbers on src.qty <= gen_numbers.r; -- clone rows qty times 
order by src.id 

お知らせ:ちょうどINSERTを実行するためにそのように指定します。

+0

新しいIDは1から3の連続番号である必要があります。 – mathguy

+0

ありがとう、私はそれを逃しました。訂正しました:-) –

+0

さて、その間に、コメントで、OPはIDがシステムによって生成されたと私に指摘されました! – mathguy