Как продублировать набор строк, изменяя только значение одного столбца, не перечисляя другие столбцы? - PullRequest
0 голосов
/ 21 сентября 2011

При наличии таблицы T(x, y, z, t, u, v, ...) возможно ли в Oracle написать этот запрос без перечисления всех столбцов (будь то в SELECT или в части INSERT)?

INSERT INTO T (x, y, z, t, u, v, ...)
SELECT 'new', y, z, t, u, v, ...
  FROM T
 WHERE x = 'old'

В результате все строки, для которых x имеет значение old , дублируются, за исключением того, что теперь x имеет значение new .

Ответы [ 3 ]

2 голосов
/ 21 сентября 2011

"возможно ли в Oracle написать этот запрос без перечисления всех столбцов (будь то в SELECT или в части INSERT)"

Нет.Единственный способ избежать ввода явной проекции - это использовать все столбцы таблицы.Вы этого не делаете, потому что хотите использовать литерал вместо столбца X.Это означает, что вам нужно перечислить все остальные столбцы в проекции SELECT.

Конечно, вам не нужно указывать столбцы в предложении INSERT.

В течение многих лет разработчики время от времени желали использовать синтаксис «исключая», что-то вроде:

select * except X from t

, но он никогда не включался в стандарт ANSI.На самом деле, я сомневаюсь, что это вообще обсуждалось.


«Ответы PLSQL приветствуются!»

Хорошо, вот подтверждение концепции, которая используетсловарь данных для создания динамического оператора вставки.

Он принимает следующие допущения:

  1. Вы хотите подставить значение только одного столбца.
  2. Столбец, который вы хотите заменить, является типом данных строки.
  3. Вы хотите клонировать все записи в исходной таблице.

Вам потребуется изменить код, если какое-либо из этих предположений неверно.

Процедуразацикливает таблицу USER_TAB_COLUMNS, сортируя столбцы в соответствии с прогнозируемым порядком таблицы.Он объединяет имена столбцов в предложение SELECT оператора INSERT, за исключением случаев, когда имя совпадает с именем замещенного столбца, когда вместо этого он объединяет предоставленный литерал.Наконец, он использует собственный динамический SQL для запуска собранного оператора INSERT.

create or replace procedure clone_minus_one 
    ( p_sub_col in user_tab_columns.column_name%type
      , p_sub_val in varchar2 )
is
    stmt varchar2(32767) := 'insert into source_table select ';
begin
    for lrec in ( select column_name
                         , column_position 
                  from  user_tab_columns.
                  where table_name = 'SOURCE_TABLE'
                  order by column_position )
    loop
        if lrec.column_position != 1
        then 
            stmt := stmt ||',';
        end if;
        if lrec.column_name != p_sub_col
        then
            stmt := stmt ||lrec.column_name;
        else
            stmt := stmt ||''''||p_sub_val||'''';
        end if;  
    end loop;
    stmt := stmt || ' from source_table';
    execute immediate stmt;
end;
/
1 голос
/ 21 сентября 2011

Вы можете делать в точности так, как вы описываете, при условии, что выбранные вами столбцы упорядочены правильно.

Следующее является действительным

INSERT INTO T 
SELECT 'new', y, z, t, u, v, ...
  FROM T
 WHERE x = 'old'

или вы можете попробовать это (грубый сценарий не проверен)

CREATE TABLE TEMPTABLE AS SELECT * FROM T WHERE X = 'Old';

UPDATE TEMPTABLE SET X='New';

INSERT INTO T (SELECT * FROM TEMPTABLE);

DROP TABLE TEMPTABLE;
0 голосов
/ 30 сентября 2011

Следующее заходит слишком далеко, чтобы избежать ввода imo, но мне нравится вызов, так что здесь все идет ...

insert into T
select * from T
where x='old';
commit;

-- update every other row to 'new'
update T
set x='new'
where rowid in
(
select rowid from
  (select rownum rnum, rowid row_id
   from T
   where x='old'
  )
where mod(rnum,2)=0
);
commit;

В 2 шага, но лично я просто запросил бы у all_tab_columns таблицы (order by column_id) и скопировал / вставил в мой скрипт / процедуру. Но может быть другая причина, чтобы избежать этого, не уверен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...