#sql #oracle #syntax-error #partitioning
Вопрос:
У меня есть таблица под названием schema.exampletab, в которой есть разделы, где имя раздела указано в форме Pxxxxxx, где x-это периоды разделов (год и месяц YYYYMM), а затем есть локальный PK. Я хочу удалить раздел, но при попытке удалить его я получаю сообщение об ошибке ORA-14006: Неверное имя раздела, но когда я пытаюсь просто запросить данные из раздела, он выбирает и отображает данные из соответствующего раздела. Обратите внимание, что я использую планировщик, который использует дату в качестве параметра, используя YYYYMMDD, поэтому я обычно подстрока.
Например, я могу запросить данные, используя следующую инструкцию:
SELECT * FROM schema.exampletab PARTITION (P202110);
Это возвращает 20 строк данных в моей таблице. Затем я пытаюсь удалить раздел, используя следующую инструкцию:
ALTER TABLE schema.exampletab DROP PARTITION (concat(P,substr('20211011',1,6)) UPDATE INDEXES;
Однако это приводит к сообщению об ошибке ORA-14006. Чтобы проверить, существует ли раздел, я попытался проверить, что схема, таблица и раздел существуют в разделе all_tab_partitions, где регистрируются все разделы в базе данных, над которой я работаю.
select partition_name from all_tab_partitions where table_owner = 'schema' and table_name = 'exampletab' and substr(partition_name,2,7) = substr('20211022',1,6);
Это возвращает имя раздела P202110 в результате запроса.
Я надеялся, что смогу использовать раздел drop с таким подзапросом:
ALTER TABLE schema.exampletab DROP PARTITION select partition_name from all_tab_partitions where table_owner = 'schema' and table_name = 'exampletab' and substr(partition_name,2,7) = substr('20211022',1,6);
Однако это все равно приводит к ошибке ORA-14006. Я пытался написать имя раздела как «P202110» и P202110 вместо родительского имени, но безуспешно.
Как я могу написать инструкцию drop partition таким образом, чтобы она удаляла раздел вместо того, чтобы выдавать ошибку ORA-14006?
Это то, что я должен делать регулярно, и поэтому было бы неплохо знать, как правильно выбирать и удалять разделы или усекать их и т. Д. Кроме того, я использую планировщик, который запускает sql-запросы с заданными интервалами, поэтому мне нужно указать даты в качестве параметра, что означает, что в моем примере кода значение YYYYMM-это значение параметра, которое анализируется, и поэтому мне нужно согласовать P с этим выводимым значением параметра, потому что, если я наберу только P202110, он фактически отбросит его.
Комментарии:
1. Имя раздела является идентификатором , поэтому оно должно быть определено во время запроса: оно участвует в этапе семантической проверки синтаксического анализа запроса, поскольку раздел должен существовать. Для динамического построения оператора необходимо использовать динамический SQL
Ответ №1:
У вас есть два варианта, учитывая, что вы используете sysdate
, чтобы узнать, какой раздел вам следует удалить.
Вариант 1 -gt; Динамический SQL, и результат должен быть выполнен вне запроса
select ' alter table '||table_owner||'.'||table_name||' drop partition '||partition_name||' update indexes ; ' from dba_Tab_partitions where table_owner = 'your_schema' and table_name = 'your_table' and partition_name = 'P'||substr(to_char(sysdate,'yyyymmdd'),1,6) ; ;
Этот запрос дает вам вывод команды, но вам нужно ее выполнить
alter table yourschema.yourtable drop partition P202110 update indexes;
Пример в моем собственном окружении
SQLgt; select ' alter table '||table_owner||'.'||table_name||' drop partition '||partition_name||' update indexes ; ' from dba_Tab_partitions where table_owner = 'FDM_DATA' and table_name = 'FDM_DIM_CUSTOMER' and partition_name = 'P_'||substr(to_char(sysdate,'yyyymmdd'),1,6) ; 'ALTERTABLE'||TABLE_OWNER||'.'||TABLE_NAME||'DROPPARTITION'||PARTITION_NAME||'UP -------------------------------------------------------------------------------- alter table FDM_DATA.FDM_DIM_CUSTOMER drop partition P_202110 update indexes ;
Вариант 2 -gt; PLSQL
Лучший вариант-использовать PLSQL
. Небольшой пример, когда вы хотите удалить только один раздел на основе текущего sysdate
. Вы можете расширить / изменить этот код, чтобы он охватывал любые временные рамки.
declare v_owner varchar2(128) := 'YOUR_SCHEMA'; v_table_name varchar2(128) := 'YOUR_TABLE'; v_partition_name varchar2(128); begin select partition_name into v_partition_name from all_tab_partitions where table_owner = v_owner and table_name = v_table_name and partition_name = 'P'||substr(to_char(sysdate,'yyyymmdd'),1,6) ; execute immediate 'alter table '||v_owner||'.'||v_table_name||' drop partition '||v_partition_name||' update indexes' ; exception when no_data_found then null; -- if there is no partition, nothing to do and no error is raised when others then raise; end; /
Комментарии:
1. Спасибо, опция PLSQL работала великолепно, и это также показало мне, почему мои объявления и последующие начальные / конечные блоки потерпели неудачу.
2. @Aite97, лучший способ поблагодарить вас за ЭТО — принять ответ. В любом случае, рад был вам помочь 😉
3. Я не знал, что могу это сделать, но теперь я должен был отметить это как принятое
4. спасибо @Aite97 за то, что приняли ответ.
Ответ №2:
Вы не можете использовать «выражения» в имени раздела
Это неправильно:
ALTER TABLE schema.exampletab DROP PARTITION (concat(P,substr('20211011',1,6)) UPDATE INDEXES;
это правильно:
ALTER TABLE schema.exampletab DROP PARTITION P20211011 UPDATE INDEXES;
Вы можете использовать этот код для динамического удаления разделов. Просто обновите C_OWNER ,C_TABLE_NAME , C_PARTITION_TEMPLATE в заголовке. Пожалуйста, обратите внимание, что команда sql строится динамически, но когда она будет готова, имя раздела будет полностью проанализировано.
declare C_OWNER varchar2(128) := 'MYOWNER'; C_TABLE_NAME varchar2(128) := 'MYTABLE'; C_PARTITION_TEMPLATE varchar2(128) := '2011'; cursor part_cur is select * from all_tab_partitions where table_owner=C_OWNER and table_name = C_TABLE_NAME and partition_name like '%'||C_PARTITION_TEMPLATE||'%' order by partition_position; BEGIN for part_rec in part_cur loop execute immediate 'ALTER TABLE "'||part_rec.table_owner||'"."'||part_rec.table_name||'"'|| ' DROP PARTITION ("'||part_rec.partition_name||'") UPDATE INDEXES'; end loop; END; /