oracle 删除索引(如果存在)
Posted
技术标签:
【中文标题】oracle 删除索引(如果存在)【英文标题】:oracle drop index if exists 【发布时间】:2011-02-12 22:30:21 【问题描述】:如果索引存在,如何删除它?
看起来很简单,但我确实在网上找到了任何东西。 我们的想法是仅在它存在时才删除它,因为如果不存在,我将出错并且我的进程将停止。
我发现这个是为了查找索引是否存在:
select index_name
from user_indexes
where table_name = 'myTable'
and index_name='myIndexName'
但是我不知道怎么搭配
DROP INDEX myIndexName
【问题讨论】:
@Samuel's 是最正确的解决方案。恕我直言,这是应该被接受的。 小心 DDL 命令的隐式提交!!那个 drop 提交,无论喜欢与否。如有必要,将其包装成一个自治事务。 之所以没有直截了当的解决方案,是因为不应该出现这种情况。这是一个配置管理问题。 @APC 这就是理想世界和我们的世界的区别。出现一些你必须做“不应该做”的事情的情况。有时,这是因为之前有人做出了错误的决定。有时,是因为形势发生了变化,突然做出了一个当时好的选择,变成了坏的选择。在我看来,“它不应该发生”是永远忽略某个功能的正当理由。这可能是为更重要的问题分配资源的正当理由,但其他几种数据库技术也提供了类似DROP IF EXISTS
的功能,我很感激它的存在。
【参考方案1】:
不检查是否存在。尝试删除,并在必要时捕获异常...
DECLARE
index_not_exists EXCEPTION;
PRAGMA EXCEPTION_INIT (index_not_exists, -1418);
BEGIN
EXECUTE IMMEDIATE 'drop index foo';
EXCEPTION
WHEN index_not_exists
THEN
NULL;
END;
/
【讨论】:
除了您可以将COUNT
替换为EXISTS
之外,这与已接受的答案相比有什么优势?
@jpmc26 接受的答案有竞争条件。索引可能已在检查计数和立即执行的行之间删除。
@Samuel 虽然这是一个有效的观点,但我希望人们不会有 2 个独立的命令试图同时在同一个对象上执行 DDL。 ;)
欢迎来到多线程的世界。 :(很好的答案+1【参考方案2】:
DECLARE
COUNT_INDEXES INTEGER;
BEGIN
SELECT COUNT ( * )
INTO COUNT_INDEXES
FROM USER_INDEXES
WHERE INDEX_NAME = 'myIndexName';
-- Edited by UltraCommit, October 1st, 2019
-- Accepted answer has a race condition.
-- The index could have been dropped between the line that checks the count
-- and the execute immediate
IF COUNT_INDEXES > 0
THEN
EXECUTE IMMEDIATE 'DROP INDEX myIndexName';
END IF;
END;
/
【讨论】:
当然,“DROP INDEX”已经检查索引是否存在,所以你现在要做两次。 这种技术引入了竞争条件。请考虑改用@Samuel 提供的答案。 我已提醒用户我接受的答案存在竞争条件。我建议改用@Samuel 提供的答案。我无法删除我的答案,因为它已在 2010 年被接受【参考方案3】:在 Oracle 中,您不能同时混合使用 DDL 和 DML。为此,您需要使用 EXECUTE IMMEDIATE 语句来解决它。
所以,首先检查索引是否存在。
其次,通过 EXECUTE IMMEDIATE 语句删除索引。
DECLARE v_Exists NUMBER;
BEGIN
v_Exists := 0;
SELECT 1 INTO v_Exists
FROM USER_INDEXES
WHERE TABLE_NAME LIKE 'myTable'
AND INDEX_NAME LIKE 'myIndexName'
IF v_Exists = 1 THEN
EXECUTE IMMEDIATE "DROP INDEX myIndexName"
ENDIF;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
这段代码不在我的脑海中,您可能需要稍微修复它,但这给出了一个想法。
希望这会有所帮助! =)
【讨论】:
【参考方案4】:我做了一个程序,可以多次调用:
DELIMITER €€
DROP PROCEDURE IF EXISTS ClearIndex€€
CREATE PROCEDURE ClearIndex(IN var_index VARCHAR(255),IN var_table VARCHAR(255))
BEGIN
SET @temp = concat('DROP INDEX ', var_index, ' ON ', var_table);
PREPARE stm1 FROM @temp;
BEGIN
DECLARE CONTINUE HANDLER FOR 1091 SELECT concat('Index ', var_index,' did not exist in ',var_table,', but was handled') AS 'INFO';
EXECUTE stm1;
END;
END €€
DELIMITER ;
现在可以多次调用:
CALL ClearIndex('employees_no_index','employees');
CALL ClearIndex('salaries_no_index','salaries');
CALL ClearIndex('titles_no_index','titles');
【讨论】:
你可以用DROP PROCEDURE
代替CREATE OR REPLACE PROCEDURE
【参考方案5】:
我希望这会有所帮助。这是所有解决方案的组合:) 顺便谢谢你的帮助!
CREATE OR REPLACE PROCEDURE CLEAR_INDEX(INDEX_NAME IN VARCHAR2) AS
BEGIN
EXECUTE IMMEDIATE 'drop index ' || INDEX_NAME;
EXCEPTION
WHEN OTHERS THEN
NULL;
END CLEAR_INDEX;
【讨论】:
您在这里忽略了所有异常,这绝对不是一个好习惯。以上是关于oracle 删除索引(如果存在)的主要内容,如果未能解决你的问题,请参考以下文章