2015-01-30 3 views
0

У меня есть следующий код, который не выполняется правильно. У меня есть данные, хранящиеся в date_tmp (varchar), которые содержат даты и недены. Я хочу перенести даты в этот столбец на date_run (дата), а данные, которые не являются датой, будут перенесены в столбец комментариев (varchar). Когда я запускаю следующий код, весь набор данных перемещается в комментарии. Он отлично работает, когда я редактирую инструкцию insert и просто запускаю строку dbms_outputline. Что я могу сделать неправильно?PL/SQL - Вставка данных с использованием исключения

DECLARE 

    CURSOR getrow IS 
    SELECT a.id, a.date_tmp 
    FROM mycolumn a 
    WHERE a.id < 1300; 

    v_date date; 

BEGIN 
    FOR i in getrow LOOP 
    BEGIN 
     v_date := to_date(i.date_tmp, 'mm/dd/yy'); 
     INSERT INTO mycolumn a(a.date_run) 
     VALUES(i.date_tmp); 

    EXCEPTION 
     WHEN OTHERS THEN  
     --dbms_output.put_line(i.date_tmp); 
     update mycolumn a 
     SET a.comments = i.date_tmp 
     where a.id = i.id; 
    END; 
    END LOOP; 
END; 
+0

попробуйте 'INSERT INTO mycolumn (date_run) VALUES (i.date_tmp);' вместо инструкции insert, поскольку она стоит прямо сейчас – Sebas

ответ

1

У вас есть insert, где вам, похоже, нужен update, как и в обработчике исключений. Так что просто изменить его на:

v_date := to_date(i.date_tmp, 'mm/dd/yy'); 
    update mycolumn 
     set date_run = v_date 
    where id = i.id; 

или вы могли бы сократить его:

update mycolumn 
     set date_run = to_date(i.date_tmp, 'mm/dd/yy') 
    where id = i.id; 
2

Вы пытаетесь вставить varchar i.date_tmp в поле даты. Вместо этого вставьте v_date.

... 
INSERT INTO mycolumn a (a.date_run) 
VALUES(v_date); 
... 

Но на самом деле ваше требование - это движение. Это требует обновления на самом деле. Так что я думаю, что вы действительно хотите сделать это:

... 
update mycolumn a 
SET a.date_run = v_date 
where a.id = i.id  
... 

А на самом деле вы могли бы иметь функцию, которая проверяет, если вы имеете действительную дату или нет, а затем вы можете быть в состоянии обрабатывать всю задачу с помощью простого обновления заявление.

create or replace function is_a_date(i_date varchar2, i_pattern varchar2) 
return date 
is 
begin 
    return to_date(i_date, i_pattern); 
exception 
    when others return null; 
end is_a_date; 

С этой функцией вы можете написать два заявления обновления

update mycolumn 
    set date_run = to_date(date_tmp,'dd/mm/yy') 
where is_a_date(date_tmp, 'dd/mm/yy') is not null; 

update mycolumn 
    set comment = date_tmp 
where is_a_date(date_tmp, 'dd/mm/yy') is null; 

Я разработал функцию таким образом, чтобы вы могли использовать его по-разному, как она возвращает вам дату или нуль, но если не исключение varchar не соответствует шаблону даты.

1

решение @hol является лучшим подходом для меня. Избегайте, когда вы можете делать циклы и процедуры, если вы можете сделать это с помощью простых записей SQL, ваш код будет быстрее. Кроме того, если вы всегда имеете данные фиксированный формат, вы можете ездить функции функции is_a_date PL/SQL и сделать это все с SQL ... но код становится немного уродливее с чем-то вроде этого:

update mycolumn 
    set date_run = to_date(date_tmp,'dd/mm/yy') 
    where substr(date_tmp,1,2) between '1' and '31' 
     and substr(date_tmp,4,2) between '1' and '12' 
     and substr(date_tmp,7,2) between '00' and '99'; 

Если вам нужна дополнительная скорость в вашем запросе или у вас есть огромный объем данных в date_tmp, поскольку функция is_a_date является детерминированной (всегда возвращает то же значение, учитывая те же значения для X, Y), вы можете создать для нее индекс :

create index mycol_idx on mycolumn(is_a_date(date_tmp)); 

И когда вы используете функцию, Oracle будет использовать индекс, как и в тех выбирает:

SELECT a.id, a.date_tmp 
    FROM mycolumn a 
    WHERE a.id < 1300 
and is_a_date(a.date_tmp) is not null; 

SELECT a.id, a.date_tmp 
    FROM mycolumn a 
    WHERE a.id < 1300 
    and (is_a_date(a.date_tmp) is not null and is_a_date(a.date_tmp)>sysdate-5); 
Смежные вопросы