Idempotent database migrations — scripts you can safely run multiple times — are a CI/CD best practice. Oracle 23ai’s IF [NOT] EXISTS syntax makes this achievable without PL/SQL wrappers. Here’s a complete migration script template.
Idempotent schema creation script:
-- ============================================================
-- Migration: v2.5.0 - Customer Preferences Schema
-- Safe to run multiple times
-- ============================================================
-- 1. Create table if it doesn't exist
CREATE TABLE customer_preferences (
preference_id NUMBER GENERATED ALWAYS AS IDENTITY,
customer_id NUMBER NOT NULL,
preference_key VARCHAR2(100) NOT NULL,
preference_val VARCHAR2(4000),
created_at TIMESTAMP DEFAULT SYSTIMESTAMP,
CONSTRAINT pk_cust_pref PRIMARY KEY (preference_id),
CONSTRAINT uq_cust_pref_key UNIQUE (customer_id, preference_key)
) IF NOT EXISTS;
-- 2. Add columns if they don't exist (new in 23ai)
ALTER TABLE customer_preferences
ADD (updated_at TIMESTAMP) IF NOT EXISTS;
ALTER TABLE customer_preferences
ADD (updated_by VARCHAR2(100)) IF NOT EXISTS;
-- 3. Create index if needed
CREATE INDEX IF NOT EXISTS idx_cust_pref_customer
ON customer_preferences (customer_id);
-- 4. Create sequence if it doesn't exist (for legacy patterns)
CREATE SEQUENCE IF NOT EXISTS seq_pref_legacy
START WITH 1 INCREMENT BY 1 NOCACHE;
-- 5. Create or replace views (always safe, no IF needed)
CREATE OR REPLACE VIEW active_preferences AS
SELECT * FROM customer_preferences
WHERE preference_val IS NOT NULL;
-- End of migration
Why this matters for DevOps:
With Flyway or Liquibase, each migration file should run exactly once. But in some environments (re-running failed migrations, cross-environment synchronization), idempotency provides a safety net. Oracle 23ai’s native IF [NOT] EXISTS removes the need for tool-specific workarounds and makes the intent clear in the script itself.
