2016-10-28 8 views
1

Я пытаюсь передать данные из одной таблицы в другую. Но в этом процессе мне нужно сделать что-то дополнительное, мне просто интересно, возможно ли сделать что-то подобное в SQL или PL/SQL.INSERT SELECT loop

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

Здесь, исходя из количества в исходной таблице, мне нужно будет вставить несколько записей. Количество может быть любого числа. Идентификатор в целевой таблице автоматически увеличивается. Я пробовал это

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

Но это не заботится о цикле qty.

+0

Я думаю, вам понадобится PL/SQL для этого, но я также задаюсь вопросом, что ваш первичный ключ будет в новой таблице. – topshot

+0

PL/SQL в порядке, а идентификатор в целевой таблице - автоматическое увеличение. Я обновил вопрос. – nicholasnet

+0

Итак, если идентификатор сгенерирован автоматически, как вы планируете убедиться, что source_id будет в порядке? Или это не имеет значения - вам просто нужно генерировать source_id и qty, и им может быть назначен любой (новый) id в «target»? – mathguy

ответ

1

Plain 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 
; 

Примечание - если идентификатор генерируется автоматически, просто перенесите 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 ИЗ ИСТОЧНИКА ПОДКЛЮЧИТЬ ...'Вам вообще не нужно предложение WITH WITH, потому что у вас уже есть таблица' SOURCE', и вам не нужно использовать псевдонимы столбцов (у вас есть имена столбцов для таблицы TARGET), и вы не нужно «ROW_NUMBER() OVER ...», если новый 'id' автогенерируется. – 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, как это. Кроме того, неясно, где вы создали новый столбец идентификаторов - на самом деле вы генерируете только два столбца. – mathguy

+0

Автор упомянул, что поле идентификатора является автоматически увеличивающимся столбцом в комментариях, а SQL-сервер поддерживает CTE –

+0

О ... Я пропустил это. – mathguy

0

Это возможно с помощью SQL. Используйте CTE для генерации количества строк, которое соответствует вашему максимальному qty из исходной таблицы, и используйте non-equi JOIN для генерации строк. Используйте row_number аналитическую функцию, чтобы присвоить каждой строке это уникальный идентификатор (если у вас есть в вашей целевой таблице, проверьте ниже на моем Edit):

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 

Заметим, что вы можете спокойно положить в Констант дорожим 1 в выход 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 

Edit: Поскольку ваша колонка целевой идентификатор автоматически увеличивается, вам не нужно row_number. Просто укажите это так, чтобы выполнить INSERT:

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 

Обратите внимание, что я добавил ORDER BY условие для обеспечения надлежащего упорядочения вставки значений.

+0

Новые идентификаторы должны быть последовательными числами от 1 до 3. – mathguy

+0

Спасибо, я пропустил это. Исправлено :-) –

+0

Ну, тем временем мне было указано, что в комментарии ОП говорит, что идентификатор генерируется системой! – mathguy