匿名块是学习和测试PL/SQL代码的强大工具,特别适合执行一次性任务或快速验证业务逻辑。
目录
一、匿名块中的DML操作
1. INSERT 示例
2. UPDATE 示例
3. DELETE 示例
二、匿名块中的动态SQL
1. EXECUTE IMMEDIATE
2. 动态游标--下篇文章会具体展开详细分享该部分内容
三、匿名块的实际应用场景
1. 数据迁移
2. 批量数据处理
3. 数据库对象检查
四、匿名块使用技巧
1. 启用DBMS_OUTPUT:
2. 调试输出:
3. 计时执行:
4. 使用绑定变量:
5. 临时禁用代码:/*...*/
一、匿名块中的DML操作
1. INSERT 示例
DECLARE
v_emp_id NUMBER := 1001;
BEGIN
INSERT INTO employees (employee_id, last_name, job_id, hire_date)
VALUES (v_emp_id, 'Smith', 'IT_PROG', SYSDATE);
COMMIT;
DBMS_OUTPUT.PUT_LINE('成功插入员工: ' || v_emp_id);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE('错误: 员工ID已存在');
ROLLBACK;
END;
/
2. UPDATE 示例
DECLARE
v_emp_id NUMBER := 100;
v_rows_updated NUMBER;
BEGIN
UPDATE employees
SET salary = salary * 1.1
WHERE employee_id = v_emp_id;
v_rows_updated := SQL%ROWCOUNT;
IF v_rows_updated = 0 THEN
DBMS_OUTPUT.PUT_LINE('未找到员工记录');
ELSE
COMMIT;
DBMS_OUTPUT.PUT_LINE('成功更新 ' || v_rows_updated || ' 条记录');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('更新失败: ' || SQLERRM);
ROLLBACK;
END;
/
3. DELETE 示例
DECLARE
v_dept_id NUMBER := 10;
v_rows_deleted NUMBER;
BEGIN
DELETE FROM employees
WHERE department_id = v_dept_id;
v_rows_deleted := SQL%ROWCOUNT;
COMMIT;
DBMS_OUTPUT.PUT_LINE('已删除 ' || v_rows_deleted || ' 条记录');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('删除失败: ' || SQLERRM);
ROLLBACK;
END;
/
二、匿名块中的动态SQL
1. EXECUTE IMMEDIATE
DECLARE
v_table_name VARCHAR2(30) := 'EMPLOYEES';
v_sql VARCHAR2(1000);
v_count NUMBER;
BEGIN
v_sql := 'SELECT COUNT(*) FROM ' || v_table_name ||
' WHERE department_id = :dept_id';
EXECUTE IMMEDIATE v_sql INTO v_count USING 10;
DBMS_OUTPUT.PUT_LINE('部门10有 ' || v_count || ' 名员工');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('执行动态SQL出错: ' || SQLERRM);
END;
/
2. 动态游标--下篇文章会具体展开详细分享该部分内容
DECLARE
TYPE emp_cur_type IS REF CURSOR;
emp_cursor emp_cur_type;
v_sql VARCHAR2(1000);
v_emp_rec employees%ROWTYPE;
v_dept_id NUMBER := 20;
BEGIN
v_sql := 'SELECT * FROM employees WHERE department_id = :dept_id';
OPEN emp_cursor FOR v_sql USING v_dept_id;
LOOP
FETCH emp_cursor INTO v_emp_rec;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_rec.employee_id || ': ' ||
v_emp_rec.last_name);
END LOOP;
CLOSE emp_cursor;
END;
/
三、匿名块的实际应用场景
1. 数据迁移
DECLARE
CURSOR src_cur IS SELECT * FROM source_table;
v_count NUMBER := 0;
BEGIN
FOR rec IN src_cur LOOP
INSERT INTO target_table VALUES rec;
v_count := v_count + 1;
-- 每1000条提交一次
IF MOD(v_count, 1000) = 0 THEN
COMMIT;
DBMS_OUTPUT.PUT_LINE('已迁移 ' || v_count || ' 条记录');
END IF;
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('迁移完成,共 ' || v_count || ' 条记录');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('迁移出错: ' || SQLERRM);
ROLLBACK;
END;
/
2. 批量数据处理
DECLARE
TYPE id_array IS TABLE OF employees.employee_id%TYPE;
v_ids id_array := id_array(101, 102, 103, 104, 105);
BEGIN
FORALL i IN 1..v_ids.COUNT
UPDATE employees
SET salary = salary * 1.1
WHERE employee_id = v_ids(i);
COMMIT;
DBMS_OUTPUT.PUT_LINE('成功更新 ' || SQL%ROWCOUNT || ' 条记录');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('批量更新失败: ' || SQLERRM);
ROLLBACK;
END;
/
3. 数据库对象检查
DECLARE
v_table_exists NUMBER;
v_table_name VARCHAR2(30) := 'TEST_TABLE';
BEGIN
SELECT COUNT(*) INTO v_table_exists
FROM user_tables
WHERE table_name = v_table_name;
IF v_table_exists = 0 THEN
EXECUTE IMMEDIATE 'CREATE TABLE ' || v_table_name ||
' (id NUMBER, name VARCHAR2(100))';
DBMS_OUTPUT.PUT_LINE('表 ' || v_table_name || ' 已创建');
ELSE
DBMS_OUTPUT.PUT_LINE('表 ' || v_table_name || ' 已存在');
END IF;
END;
/
四、匿名块使用技巧
1. 启用DBMS_OUTPUT:
SET SERVEROUTPUT ON SIZE 1000000
2. 调试输出:
DBMS_OUTPUT.PUT_LINE('变量值: ' || v_variable);
3. 计时执行:
DECLARE
v_start TIMESTAMP := SYSTIMESTAMP;
BEGIN
-- 执行代码
DBMS_OUTPUT.PUT_LINE('执行时间: ' || (SYSTIMESTAMP - v_start));
END;
/
4. 使用绑定变量:
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM employees WHERE department_id = :dept_id'
INTO v_count USING 10;
5. 临时禁用代码:/*...*/
/*
-- 被注释的代码
DBMS_OUTPUT.PUT_LINE('这段代码不会执行');
*/