How to Generate UUID with SYS_GUID()
Oracle's SYS_GUID() function generates a 16-byte globally unique identifier (GUID) stored as RAW(16):
-- Generate a GUID (returns RAW(16))
SELECT SYS_GUID() FROM DUAL;
-- Result: 550E8400E29B41D4A716446655440000 (hex format)
-- Create table with GUID as primary key
CREATE TABLE users (
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
name VARCHAR2(100) NOT NULL,
email VARCHAR2(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert without specifying ID (auto-generated)
INSERT INTO users (name, email)
VALUES ('John Doe', 'john@example.com');
-- Query by GUID
SELECT * FROM users
WHERE id = HEXTORAW('550E8400E29B41D4A716446655440000');
-- Commit changes
COMMIT;
Note: SYS_GUID() returns RAW(16) in hexadecimal format without hyphens. Use conversion functions to format as standard UUID with hyphens.
Converting Between RAW and UUID Format
Create functions to convert between Oracle's RAW format and standard UUID string format:
-- Function to convert RAW to UUID string format
CREATE OR REPLACE FUNCTION RAW_TO_UUID(p_raw IN RAW)
RETURN VARCHAR2
IS
v_hex VARCHAR2(32);
BEGIN
v_hex := RAWTOHEX(p_raw);
RETURN LOWER(
SUBSTR(v_hex, 1, 8) || '-' ||
SUBSTR(v_hex, 9, 4) || '-' ||
SUBSTR(v_hex, 13, 4) || '-' ||
SUBSTR(v_hex, 17, 4) || '-' ||
SUBSTR(v_hex, 21, 12)
);
END;
/
-- Function to convert UUID string to RAW
CREATE OR REPLACE FUNCTION UUID_TO_RAW(p_uuid IN VARCHAR2)
RETURN RAW
IS
BEGIN
RETURN HEXTORAW(REPLACE(p_uuid, '-', ''));
END;
/
-- Usage examples
SELECT RAW_TO_UUID(SYS_GUID()) AS uuid FROM DUAL;
-- Result: 550e8400-e29b-41d4-a716-446655440000
SELECT UUID_TO_RAW('550e8400-e29b-41d4-a716-446655440000') AS raw FROM DUAL;
-- Result: 550E8400E29B41D4A716446655440000
Create Table with Formatted UUID Display
Use views or computed columns to display UUIDs in standard format:
-- Create base table
CREATE TABLE products (
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
name VARCHAR2(200) NOT NULL,
sku VARCHAR2(50) UNIQUE,
price NUMBER(10,2)
);
-- Create view with formatted UUIDs
CREATE OR REPLACE VIEW products_view AS
SELECT
RAW_TO_UUID(id) AS id,
name,
sku,
price
FROM products;
-- Insert data
INSERT INTO products (name, sku, price)
VALUES ('Laptop', 'LAP-001', 999.99);
-- Query view (displays formatted UUID)
SELECT * FROM products_view;
-- Query base table by UUID string
SELECT * FROM products
WHERE id = UUID_TO_RAW('550e8400-e29b-41d4-a716-446655440000');
Storage: RAW(16) vs VARCHAR2(36)
| Storage Type | Size | Performance | Recommendation |
|---|---|---|---|
| RAW(16) | 16 bytes | ✓ Fast indexes | ✓ Recommended |
| VARCHAR2(36) | 36+ bytes | Slower indexes | Not recommended |
| CHAR(36) | 36 bytes (fixed) | Slower indexes | Not recommended |
Best Practice: Always use RAW(16) for UUID storage. It's 55% smaller than VARCHAR2(36) and provides better index performance.
Indexing UUID Columns
Oracle efficiently indexes RAW columns for optimal query performance:
-- B-tree index on UUID primary key (automatic)
CREATE TABLE orders (
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
customer_id RAW(16) NOT NULL,
total NUMBER(10,2)
);
-- Create index on foreign key
CREATE INDEX idx_orders_customer ON orders(customer_id);
-- Composite index
CREATE INDEX idx_customer_created
ON orders(customer_id, created_at);
-- Function-based index for UUID conversion
CREATE INDEX idx_users_uuid_format
ON users(RAW_TO_UUID(id));
-- Check index usage
SELECT index_name, table_name, uniqueness
FROM user_indexes
WHERE table_name = 'USERS';
-- Analyze table statistics
EXEC DBMS_STATS.GATHER_TABLE_STATS('YOUR_SCHEMA', 'USERS');
Using UUID with Oracle Sequences
While UUIDs don't require sequences, you can combine both for specific use cases:
-- Table with both UUID and sequence number
CREATE TABLE transactions (
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
transaction_number NUMBER GENERATED ALWAYS AS IDENTITY,
amount NUMBER(10,2),
description VARCHAR2(500)
);
-- UUID for global uniqueness, sequence for human-readable ordering
INSERT INTO transactions (amount, description)
VALUES (150.00, 'Payment received');
-- Query combining both
SELECT
RAW_TO_UUID(id) AS uuid,
transaction_number,
amount,
description
FROM transactions
ORDER BY transaction_number;
PL/SQL Procedures with UUID
Create stored procedures that work with UUIDs:
-- Procedure to create user and return UUID
CREATE OR REPLACE PROCEDURE create_user (
p_name IN VARCHAR2,
p_email IN VARCHAR2,
p_uuid OUT VARCHAR2
)
IS
v_id RAW(16);
BEGIN
v_id := SYS_GUID();
INSERT INTO users (id, name, email)
VALUES (v_id, p_name, p_email);
p_uuid := RAW_TO_UUID(v_id);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END;
/
-- Usage
DECLARE
v_new_uuid VARCHAR2(36);
BEGIN
create_user('Alice Smith', 'alice@example.com', v_new_uuid);
DBMS_OUTPUT.PUT_LINE('Created user with UUID: ' || v_new_uuid);
END;
/
JDBC Integration (Java)
Working with Oracle UUIDs in Java applications:
import java.sql.*;
import java.util.UUID;
public class OracleUuidExample {
public static void insertUser(Connection conn, String name, String email)
throws SQLException {
String sql = "INSERT INTO users (id, name, email) VALUES (?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
// Generate UUID
UUID uuid = UUID.randomUUID();
byte[] bytes = convertUuidToBytes(uuid);
pstmt.setBytes(1, bytes);
pstmt.setString(2, name);
pstmt.setString(3, email);
pstmt.executeUpdate();
}
}
private static byte[] convertUuidToBytes(UUID uuid) {
byte[] bytes = new byte[16];
long msb = uuid.getMostSignificantBits();
long lsb = uuid.getLeastSignificantBits();
for (int i = 0; i < 8; i++) {
bytes[i] = (byte) (msb >>> (56 - i * 8));
bytes[i + 8] = (byte) (lsb >>> (56 - i * 8));
}
return bytes;
}
}
cx_Oracle Integration (Python)
Using UUIDs with Oracle in Python:
import cx_Oracle
import uuid
# Connect to Oracle
conn = cx_Oracle.connect('user/password@localhost:1521/XEPDB1')
cursor = conn.cursor()
# Generate UUID and convert to bytes
user_uuid = uuid.uuid4()
uuid_bytes = user_uuid.bytes
# Insert with UUID
cursor.execute("""
INSERT INTO users (id, name, email)
VALUES (:id, :name, :email)
""", {
'id': uuid_bytes,
'name': 'Bob Wilson',
'email': 'bob@example.com'
})
conn.commit()
# Query and convert back to UUID
cursor.execute("SELECT id, name FROM users WHERE ROWNUM = 1")
row = cursor.fetchone()
stored_uuid = uuid.UUID(bytes=bytes(row[0]))
print(f"Stored UUID: {stored_uuid}")
cursor.close()
conn.close()