Oracle SQL and PL/SQL Examples
Oracle SQL and PL/SQL Examples
Practical examples for HeliosDB’s Oracle 23ai compatibility, including connection examples, SQL queries, PL/SQL programs, and driver-specific code.
Table of Contents
- Connection Examples
- SQL Examples
- Hierarchical Queries
- JSON Operations
- PL/SQL Examples
- DBMS Package Examples
- JDBC Examples
- OCI Examples
- Python Examples
- Node.js Examples
- Error Handling Examples
Connection Examples
SQL*Plus Connections
-- Easy Connect syntaxsqlplus admin/password@//localhost:1521/heliosdb
-- With TNS name (requires tnsnames.ora)sqlplus admin/password@HELIOSDB
-- Connect as SYSDBA rolesqlplus admin/password@//localhost:1521/heliosdb AS SYSDBA
-- Connect with SSL/TLSsqlplus admin/password@tcps://localhost:2484/heliosdb
-- Silent mode for scriptssqlplus -s admin/password@//localhost:1521/heliosdb @script.sqlConnection Verification
-- Verify connectionSELECT USER, SYS_CONTEXT('USERENV', 'DB_NAME') AS database, SYS_CONTEXT('USERENV', 'HOST') AS host, SYS_CONTEXT('USERENV', 'SERVICE_NAME') AS serviceFROM DUAL;
-- Check Oracle compatibility versionSELECT * FROM v$version;
-- View NLS parametersSELECT * FROM nls_session_parameters ORDER BY parameter;
-- Check current schemaSELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL;SQL Examples
Basic CRUD Operations
-- Create table with Oracle-specific featuresCREATE TABLE employees ( employee_id NUMBER(10) PRIMARY KEY, first_name VARCHAR2(50) NOT NULL, last_name VARCHAR2(50) NOT NULL, email VARCHAR2(100) UNIQUE, hire_date DATE DEFAULT SYSDATE, salary NUMBER(10,2) CHECK (salary > 0), department_id NUMBER(5), manager_id NUMBER(10), created_at TIMESTAMP DEFAULT SYSTIMESTAMP);
-- Create sequenceCREATE SEQUENCE emp_seq START WITH 1000 INCREMENT BY 1 CACHE 20;
-- Insert with sequenceINSERT INTO employees (employee_id, first_name, last_name, email, salary, department_id)VALUES (emp_seq.NEXTVAL, 'John', 'Smith', 'jsmith@example.com', 75000, 10);
-- Insert multiple rowsINSERT ALL INTO employees VALUES (emp_seq.NEXTVAL, 'Jane', 'Doe', 'jdoe@example.com', SYSDATE, 80000, 20, NULL, SYSTIMESTAMP) INTO employees VALUES (emp_seq.NEXTVAL, 'Bob', 'Johnson', 'bjohnson@example.com', SYSDATE, 65000, 10, NULL, SYSTIMESTAMP)SELECT * FROM DUAL;
-- Update with RETURNING clauseUPDATE employeesSET salary = salary * 1.1WHERE department_id = 10RETURNING employee_id, salary INTO :emp_id, :new_salary;
-- MERGE statement (upsert)MERGE INTO employees eUSING (SELECT 1001 AS emp_id, 'Updated' AS first_name FROM DUAL) srcON (e.employee_id = src.emp_id)WHEN MATCHED THEN UPDATE SET e.first_name = src.first_nameWHEN NOT MATCHED THEN INSERT (employee_id, first_name, last_name, email, salary) VALUES (src.emp_id, src.first_name, 'New', 'new@example.com', 50000);
-- Delete with subqueryDELETE FROM employeesWHERE department_id IN ( SELECT department_id FROM departments WHERE location = 'Closed');Oracle Functions
-- String functions with Oracle-specific behaviorSELECT INSTR('Hello World', 'o', 1, 2) AS second_o, -- 8 (2nd occurrence) SUBSTR('Hello World', -5) AS last_five, -- 'World' SUBSTR('Hello World', 1, 5) AS first_five, -- 'Hello' LPAD('123', 10, '0') AS padded, -- '0000000123' TRANSLATE('Hello', 'el', 'ip') AS translated, -- 'Hippo' REPLACE('Hello World', 'World', 'Oracle') AS replacedFROM DUAL;
-- DECODE and NVL examplesSELECT employee_id, DECODE(status, 'A', 'Active', 'I', 'Inactive', 'T', 'Terminated', 'Unknown') AS status_desc, NVL(commission, 0) AS commission, NVL2(manager_id, 'Has Manager', 'Top Level') AS manager_status, COALESCE(bonus, commission, 0) AS total_bonusFROM employees;
-- Date functionsSELECT SYSDATE AS current_date, SYSTIMESTAMP AS current_timestamp, ADD_MONTHS(SYSDATE, 3) AS three_months_later, MONTHS_BETWEEN(DATE '2024-06-15', DATE '2024-01-10') AS months_diff, LAST_DAY(SYSDATE) AS end_of_month, NEXT_DAY(SYSDATE, 'MONDAY') AS next_monday, TRUNC(SYSDATE, 'MM') AS first_of_month, TO_CHAR(SYSDATE, 'Day, DD Month YYYY HH24:MI:SS') AS formatted_dateFROM DUAL;
-- CASE expressionSELECT employee_id, salary, CASE WHEN salary >= 100000 THEN 'Executive' WHEN salary >= 75000 THEN 'Senior' WHEN salary >= 50000 THEN 'Mid-Level' ELSE 'Junior' END AS salary_gradeFROM employees;Analytic Functions
-- Ranking functionsSELECT employee_id, department_id, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS overall_rank, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank, RANK() OVER (ORDER BY salary DESC) AS rank_with_gaps, DENSE_RANK() OVER (ORDER BY salary DESC) AS rank_no_gaps, NTILE(4) OVER (ORDER BY salary DESC) AS quartileFROM employees;
-- Running totals and moving averagesSELECT order_date, amount, SUM(amount) OVER (ORDER BY order_date) AS running_total, AVG(amount) OVER (ORDER BY order_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_3, SUM(amount) OVER (PARTITION BY TRUNC(order_date, 'MM') ORDER BY order_date) AS monthly_runningFROM orders;
-- LAG and LEADSELECT employee_id, hire_date, salary, LAG(salary, 1, 0) OVER (ORDER BY hire_date) AS prev_salary, LEAD(salary, 1, 0) OVER (ORDER BY hire_date) AS next_salary, salary - LAG(salary, 1, salary) OVER (ORDER BY hire_date) AS salary_changeFROM employees;
-- FIRST_VALUE and LAST_VALUESELECT department_id, employee_id, salary, FIRST_VALUE(salary) OVER ( PARTITION BY department_id ORDER BY salary DESC ) AS highest_in_dept, LAST_VALUE(salary) OVER ( PARTITION BY department_id ORDER BY salary DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS lowest_in_deptFROM employees;
-- LISTAGG aggregationSELECT department_id, LISTAGG(last_name, ', ') WITHIN GROUP (ORDER BY last_name) AS employee_listFROM employeesGROUP BY department_id;PIVOT and UNPIVOT
-- PIVOT example: Sales by quarterSELECT *FROM ( SELECT product, quarter, amount FROM sales)PIVOT ( SUM(amount) AS total FOR quarter IN ('Q1' AS q1, 'Q2' AS q2, 'Q3' AS q3, 'Q4' AS q4));
-- UNPIVOT example: Convert columns to rowsSELECT product, quarter, amountFROM quarterly_salesUNPIVOT ( amount FOR quarter IN (q1 AS 'Q1', q2 AS 'Q2', q3 AS 'Q3', q4 AS 'Q4'));Hierarchical Queries
Basic CONNECT BY
-- Employee hierarchy with indentationSELECT LEVEL, LPAD(' ', (LEVEL - 1) * 4) || first_name || ' ' || last_name AS employee_name, employee_id, manager_id, salaryFROM employeesSTART WITH manager_id IS NULLCONNECT BY PRIOR employee_id = manager_idORDER SIBLINGS BY last_name;Advanced Hierarchical Features
-- With SYS_CONNECT_BY_PATHSELECT employee_id, first_name || ' ' || last_name AS employee_name, LEVEL AS depth, SYS_CONNECT_BY_PATH(last_name, '/') AS path, CONNECT_BY_ROOT last_name AS root_manager, CONNECT_BY_ISLEAF AS is_leafFROM employeesSTART WITH manager_id IS NULLCONNECT BY PRIOR employee_id = manager_id;
-- Cycle detection with NOCYCLESELECT employee_id, CONNECT_BY_ISCYCLE AS is_cycle, SYS_CONNECT_BY_PATH(employee_id, '/') AS pathFROM employeesSTART WITH manager_id IS NULLCONNECT BY NOCYCLE PRIOR employee_id = manager_id;
-- Bill of materials hierarchySELECT LEVEL, LPAD(' ', (LEVEL-1) * 2) || component_name AS component, parent_id, component_id, quantity, SYS_CONNECT_BY_PATH(component_name, ' > ') AS assembly_pathFROM bill_of_materialsSTART WITH parent_id IS NULLCONNECT BY PRIOR component_id = parent_id;
-- Category tree with aggregationSELECT LEVEL, category_id, category_name, CONNECT_BY_ROOT category_name AS root_category, (SELECT COUNT(*) FROM products p WHERE p.category_id = c.category_id) AS product_countFROM categories cSTART WITH parent_category_id IS NULLCONNECT BY PRIOR category_id = parent_category_idORDER SIBLINGS BY category_name;JSON Operations
JSON_VALUE and JSON_QUERY
-- Extract scalar valuesSELECT customer_id, JSON_VALUE(profile, '$.name') AS name, JSON_VALUE(profile, '$.email') AS email, JSON_VALUE(profile, '$.address.city') AS city, JSON_VALUE(profile, '$.age' RETURNING NUMBER) AS ageFROM customersWHERE JSON_VALUE(profile, '$.status') = 'active';
-- Extract objects and arraysSELECT order_id, JSON_QUERY(order_data, '$.items') AS items_array, JSON_QUERY(order_data, '$.shipping_address') AS shippingFROM orders;JSON_TABLE
-- Convert JSON array to rowsSELECT o.order_id, o.order_date, jt.item_id, jt.product_name, jt.quantity, jt.price, jt.quantity * jt.price AS line_totalFROM orders o,JSON_TABLE(o.order_data, '$.items[*]' COLUMNS ( item_id NUMBER PATH '$.id', product_name VARCHAR2(100) PATH '$.product', quantity NUMBER PATH '$.qty', price NUMBER PATH '$.price' )) jt;
-- Nested JSON with multiple levelsSELECT c.customer_id, addr.street, addr.city, addr.state, addr.zipFROM customers c,JSON_TABLE(c.profile, '$.addresses[*]' COLUMNS ( address_type VARCHAR2(20) PATH '$.type', street VARCHAR2(100) PATH '$.street', city VARCHAR2(50) PATH '$.city', state VARCHAR2(2) PATH '$.state', zip VARCHAR2(10) PATH '$.zip' )) addrWHERE addr.address_type = 'shipping';JSON Construction
-- Build JSON objectSELECT JSON_OBJECT( 'employee_id' VALUE employee_id, 'name' VALUE first_name || ' ' || last_name, 'department' VALUE department_id, 'salary' VALUE salary, 'hire_date' VALUE TO_CHAR(hire_date, 'YYYY-MM-DD') ) AS employee_jsonFROM employees;
-- Build JSON arraySELECT JSON_ARRAY(first_name, last_name, email) AS contact_arrayFROM employees;
-- Aggregate to JSONSELECT department_id, JSON_ARRAYAGG( JSON_OBJECT( 'id' VALUE employee_id, 'name' VALUE first_name || ' ' || last_name ) ORDER BY last_name ) AS employees_jsonFROM employeesGROUP BY department_id;
-- Complex JSON aggregationSELECT JSON_OBJECT( 'department_id' VALUE d.department_id, 'department_name' VALUE d.department_name, 'employee_count' VALUE COUNT(e.employee_id), 'total_salary' VALUE SUM(e.salary), 'employees' VALUE JSON_ARRAYAGG( JSON_OBJECT( 'id' VALUE e.employee_id, 'name' VALUE e.first_name || ' ' || e.last_name ) ) ) AS dept_summaryFROM departments dLEFT JOIN employees e ON d.department_id = e.department_idGROUP BY d.department_id, d.department_name;PL/SQL Examples
Anonymous Blocks
-- Basic anonymous blockDECLARE v_name VARCHAR2(100); v_salary NUMBER; v_hire_date DATE;BEGIN SELECT first_name || ' ' || last_name, salary, hire_date INTO v_name, v_salary, v_hire_date FROM employees WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_name); DBMS_OUTPUT.PUT_LINE('Salary: ' || TO_CHAR(v_salary, '$999,999.99')); DBMS_OUTPUT.PUT_LINE('Hire Date: ' || TO_CHAR(v_hire_date, 'DD-MON-YYYY'));EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Employee not found'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);END;/Stored Procedures
-- Procedure with IN/OUT parametersCREATE OR REPLACE PROCEDURE give_raise( p_employee_id IN NUMBER, p_percent IN NUMBER, p_new_salary OUT NUMBER, p_status OUT VARCHAR2) AS v_current_salary NUMBER;BEGIN -- Get current salary SELECT salary INTO v_current_salary FROM employees WHERE employee_id = p_employee_id;
-- Calculate new salary p_new_salary := v_current_salary * (1 + p_percent / 100);
-- Update the salary UPDATE employees SET salary = p_new_salary WHERE employee_id = p_employee_id;
IF SQL%ROWCOUNT > 0 THEN p_status := 'SUCCESS'; COMMIT; ELSE p_status := 'NO_UPDATE'; END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN p_new_salary := 0; p_status := 'EMPLOYEE_NOT_FOUND'; WHEN OTHERS THEN p_new_salary := 0; p_status := 'ERROR: ' || SQLERRM; ROLLBACK;END give_raise;/
-- Call the procedureDECLARE v_new_salary NUMBER; v_status VARCHAR2(200);BEGIN give_raise(100, 10, v_new_salary, v_status); DBMS_OUTPUT.PUT_LINE('New Salary: ' || v_new_salary); DBMS_OUTPUT.PUT_LINE('Status: ' || v_status);END;/Functions
-- Function returning scalar valueCREATE OR REPLACE FUNCTION calculate_bonus( p_employee_id IN NUMBER, p_bonus_percent IN NUMBER DEFAULT 10) RETURN NUMBER AS v_salary NUMBER; v_years_of_service NUMBER; v_bonus NUMBER;BEGIN SELECT salary, TRUNC(MONTHS_BETWEEN(SYSDATE, hire_date) / 12) INTO v_salary, v_years_of_service FROM employees WHERE employee_id = p_employee_id;
-- Calculate bonus with service multiplier v_bonus := v_salary * (p_bonus_percent / 100) * CASE WHEN v_years_of_service >= 10 THEN 1.5 WHEN v_years_of_service >= 5 THEN 1.25 ELSE 1.0 END;
RETURN ROUND(v_bonus, 2);
EXCEPTION WHEN NO_DATA_FOUND THEN RETURN NULL;END calculate_bonus;/
-- Use function in SQLSELECT employee_id, first_name || ' ' || last_name AS name, salary, calculate_bonus(employee_id) AS bonus, calculate_bonus(employee_id, 15) AS higher_bonusFROM employeesWHERE department_id = 10;Cursor Examples
-- Explicit cursor with parametersDECLARE CURSOR emp_cursor(p_dept_id NUMBER) IS SELECT employee_id, first_name, last_name, salary FROM employees WHERE department_id = p_dept_id ORDER BY salary DESC;
v_emp emp_cursor%ROWTYPE; v_total_salary NUMBER := 0; v_count NUMBER := 0;BEGIN OPEN emp_cursor(10); LOOP FETCH emp_cursor INTO v_emp; EXIT WHEN emp_cursor%NOTFOUND;
v_total_salary := v_total_salary + v_emp.salary; v_count := v_count + 1;
DBMS_OUTPUT.PUT_LINE( RPAD(v_emp.first_name || ' ' || v_emp.last_name, 30) || TO_CHAR(v_emp.salary, '$999,999.99') ); END LOOP;
DBMS_OUTPUT.PUT_LINE('---'); DBMS_OUTPUT.PUT_LINE('Total: ' || v_count || ' employees'); DBMS_OUTPUT.PUT_LINE('Total Salary: ' || TO_CHAR(v_total_salary, '$9,999,999.99')); DBMS_OUTPUT.PUT_LINE('Average: ' || TO_CHAR(v_total_salary/v_count, '$999,999.99'));
CLOSE emp_cursor;END;/
-- Cursor FOR loop (simpler syntax)BEGIN FOR emp_rec IN ( SELECT employee_id, first_name, last_name, salary FROM employees WHERE department_id = 20 ORDER BY salary DESC ) LOOP DBMS_OUTPUT.PUT_LINE(emp_rec.first_name || ': ' || emp_rec.salary); END LOOP;END;/BULK COLLECT and FORALL
-- BULK COLLECT exampleDECLARE TYPE emp_tab_type IS TABLE OF employees%ROWTYPE; v_employees emp_tab_type;BEGIN -- Bulk collect all employees SELECT * BULK COLLECT INTO v_employees FROM employees WHERE department_id = 10;
DBMS_OUTPUT.PUT_LINE('Found ' || v_employees.COUNT || ' employees');
-- Process the collection FOR i IN 1..v_employees.COUNT LOOP DBMS_OUTPUT.PUT_LINE( v_employees(i).employee_id || ': ' || v_employees(i).first_name || ' ' || v_employees(i).last_name ); END LOOP;END;/
-- BULK COLLECT with LIMITDECLARE CURSOR emp_cur IS SELECT * FROM employees; TYPE emp_tab IS TABLE OF employees%ROWTYPE; v_employees emp_tab; v_batch_size CONSTANT PLS_INTEGER := 100;BEGIN OPEN emp_cur; LOOP FETCH emp_cur BULK COLLECT INTO v_employees LIMIT v_batch_size; EXIT WHEN v_employees.COUNT = 0;
-- Process batch DBMS_OUTPUT.PUT_LINE('Processing batch of ' || v_employees.COUNT);
-- Do something with the batch FOR i IN 1..v_employees.COUNT LOOP -- Process each record NULL; END LOOP; END LOOP; CLOSE emp_cur;END;/
-- FORALL for bulk DMLDECLARE TYPE emp_id_tab IS TABLE OF employees.employee_id%TYPE; TYPE salary_tab IS TABLE OF employees.salary%TYPE; v_emp_ids emp_id_tab; v_new_salaries salary_tab;BEGIN -- Populate the collections SELECT employee_id, salary * 1.05 BULK COLLECT INTO v_emp_ids, v_new_salaries FROM employees WHERE department_id = 10;
-- Bulk update FORALL i IN 1..v_emp_ids.COUNT UPDATE employees SET salary = v_new_salaries(i) WHERE employee_id = v_emp_ids(i);
DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' employees'); COMMIT;END;/Packages
-- Package specificationCREATE OR REPLACE PACKAGE employee_pkg AS -- Public types TYPE emp_rec IS RECORD ( employee_id employees.employee_id%TYPE, full_name VARCHAR2(100), salary employees.salary%TYPE );
TYPE emp_tab IS TABLE OF emp_rec;
-- Public procedures and functions PROCEDURE hire_employee( p_first_name IN VARCHAR2, p_last_name IN VARCHAR2, p_email IN VARCHAR2, p_salary IN NUMBER, p_dept_id IN NUMBER, p_emp_id OUT NUMBER );
PROCEDURE terminate_employee( p_employee_id IN NUMBER );
FUNCTION get_employees_by_dept( p_dept_id IN NUMBER ) RETURN emp_tab;
FUNCTION get_department_salary_total( p_dept_id IN NUMBER ) RETURN NUMBER;
END employee_pkg;/
-- Package bodyCREATE OR REPLACE PACKAGE BODY employee_pkg AS
-- Private variable g_last_hire_date DATE;
-- Private function FUNCTION generate_email( p_first_name VARCHAR2, p_last_name VARCHAR2 ) RETURN VARCHAR2 IS BEGIN RETURN LOWER(SUBSTR(p_first_name, 1, 1) || p_last_name || '@example.com'); END generate_email;
PROCEDURE hire_employee( p_first_name IN VARCHAR2, p_last_name IN VARCHAR2, p_email IN VARCHAR2, p_salary IN NUMBER, p_dept_id IN NUMBER, p_emp_id OUT NUMBER ) AS v_email VARCHAR2(100); BEGIN -- Generate email if not provided v_email := NVL(p_email, generate_email(p_first_name, p_last_name));
-- Get next sequence value SELECT emp_seq.NEXTVAL INTO p_emp_id FROM DUAL;
-- Insert the employee INSERT INTO employees ( employee_id, first_name, last_name, email, hire_date, salary, department_id ) VALUES ( p_emp_id, p_first_name, p_last_name, v_email, SYSDATE, p_salary, p_dept_id );
g_last_hire_date := SYSDATE; COMMIT;
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN RAISE_APPLICATION_ERROR(-20001, 'Email already exists'); END hire_employee;
PROCEDURE terminate_employee( p_employee_id IN NUMBER ) AS BEGIN DELETE FROM employees WHERE employee_id = p_employee_id;
IF SQL%ROWCOUNT = 0 THEN RAISE_APPLICATION_ERROR(-20002, 'Employee not found'); END IF;
COMMIT; END terminate_employee;
FUNCTION get_employees_by_dept( p_dept_id IN NUMBER ) RETURN emp_tab AS v_result emp_tab := emp_tab(); BEGIN FOR rec IN ( SELECT employee_id, first_name || ' ' || last_name AS full_name, salary FROM employees WHERE department_id = p_dept_id ) LOOP v_result.EXTEND; v_result(v_result.COUNT).employee_id := rec.employee_id; v_result(v_result.COUNT).full_name := rec.full_name; v_result(v_result.COUNT).salary := rec.salary; END LOOP;
RETURN v_result; END get_employees_by_dept;
FUNCTION get_department_salary_total( p_dept_id IN NUMBER ) RETURN NUMBER AS v_total NUMBER; BEGIN SELECT SUM(salary) INTO v_total FROM employees WHERE department_id = p_dept_id;
RETURN NVL(v_total, 0); END get_department_salary_total;
END employee_pkg;/
-- Using the packageDECLARE v_emp_id NUMBER; v_employees employee_pkg.emp_tab;BEGIN -- Hire a new employee employee_pkg.hire_employee( p_first_name => 'New', p_last_name => 'Employee', p_email => NULL, -- Will be generated p_salary => 60000, p_dept_id => 10, p_emp_id => v_emp_id ); DBMS_OUTPUT.PUT_LINE('Hired employee ID: ' || v_emp_id);
-- Get department total DBMS_OUTPUT.PUT_LINE('Dept 10 total salary: ' || employee_pkg.get_department_salary_total(10));END;/Triggers
-- Audit triggerCREATE OR REPLACE TRIGGER emp_audit_triggerAFTER INSERT OR UPDATE OR DELETE ON employeesFOR EACH ROWDECLARE v_action VARCHAR2(10);BEGIN IF INSERTING THEN v_action := 'INSERT'; INSERT INTO emp_audit (audit_id, employee_id, action, action_date, new_salary) VALUES (audit_seq.NEXTVAL, :NEW.employee_id, v_action, SYSDATE, :NEW.salary); ELSIF UPDATING THEN v_action := 'UPDATE'; INSERT INTO emp_audit (audit_id, employee_id, action, action_date, old_salary, new_salary) VALUES (audit_seq.NEXTVAL, :NEW.employee_id, v_action, SYSDATE, :OLD.salary, :NEW.salary); ELSIF DELETING THEN v_action := 'DELETE'; INSERT INTO emp_audit (audit_id, employee_id, action, action_date, old_salary) VALUES (audit_seq.NEXTVAL, :OLD.employee_id, v_action, SYSDATE, :OLD.salary); END IF;END;/
-- Before insert trigger for auto-populationCREATE OR REPLACE TRIGGER emp_before_insertBEFORE INSERT ON employeesFOR EACH ROWBEGIN -- Auto-generate ID if not provided IF :NEW.employee_id IS NULL THEN SELECT emp_seq.NEXTVAL INTO :NEW.employee_id FROM DUAL; END IF;
-- Set created timestamp :NEW.created_at := SYSTIMESTAMP;
-- Uppercase email :NEW.email := UPPER(:NEW.email);END;/DBMS Package Examples
DBMS_OUTPUT
SET SERVEROUTPUT ON SIZE 1000000
BEGIN DBMS_OUTPUT.ENABLE(1000000); DBMS_OUTPUT.PUT_LINE('=== Employee Report ==='); DBMS_OUTPUT.PUT('Processing...'); DBMS_OUTPUT.NEW_LINE;
FOR emp IN (SELECT * FROM employees WHERE ROWNUM <= 5) LOOP DBMS_OUTPUT.PUT_LINE(' ' || emp.first_name || ' ' || emp.last_name); END LOOP;
DBMS_OUTPUT.PUT_LINE('=== End of Report ===');END;/DBMS_SCHEDULER
-- Create a scheduled jobBEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'DAILY_STATS_GATHER', job_type => 'STORED_PROCEDURE', job_action => 'DBMS_STATS.GATHER_SCHEMA_STATS', number_of_arguments => 1, start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=DAILY; BYHOUR=2; BYMINUTE=0', enabled => FALSE, comments => 'Gather statistics daily at 2 AM' );
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE( job_name => 'DAILY_STATS_GATHER', argument_position => 1, argument_value => 'HR' );
DBMS_SCHEDULER.ENABLE('DAILY_STATS_GATHER');END;/
-- Run job immediatelyBEGIN DBMS_SCHEDULER.RUN_JOB('DAILY_STATS_GATHER');END;/
-- Check job statusSELECT job_name, state, last_start_date, next_run_dateFROM user_scheduler_jobs;DBMS_METADATA
-- Get table DDLSELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES') FROM DUAL;
-- Get all indexes for a tableSELECT DBMS_METADATA.GET_DEPENDENT_DDL('INDEX', 'EMPLOYEES') FROM DUAL;
-- With transform parametersBEGIN DBMS_METADATA.SET_TRANSFORM_PARAM( DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', FALSE ); DBMS_METADATA.SET_TRANSFORM_PARAM( DBMS_METADATA.SESSION_TRANSFORM, 'TABLESPACE', FALSE );END;/
SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES') FROM DUAL;JDBC Examples
Basic JDBC Connection
import java.sql.*;import oracle.jdbc.OracleConnection;import oracle.jdbc.pool.OracleDataSource;
public class BasicJdbcExample {
private static final String URL = "jdbc:oracle:thin:@//localhost:1521/heliosdb"; private static final String USER = "admin"; private static final String PASSWORD = "password";
public static void main(String[] args) throws SQLException { OracleDataSource ods = new OracleDataSource(); ods.setURL(URL); ods.setUser(USER); ods.setPassword(PASSWORD);
try (Connection conn = ods.getConnection()) { System.out.println("Connected to HeliosDB");
// Simple query try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery( "SELECT employee_id, first_name, last_name, salary " + "FROM employees WHERE department_id = 10")) {
while (rs.next()) { System.out.printf("%d: %s %s - $%.2f%n", rs.getInt("employee_id"), rs.getString("first_name"), rs.getString("last_name"), rs.getDouble("salary")); } } } }}Prepared Statements and Batching
import java.sql.*;
public class PreparedStatementExample {
public void insertEmployees(Connection conn, List<Employee> employees) throws SQLException {
String sql = "INSERT INTO employees " + "(employee_id, first_name, last_name, email, salary, department_id) " + "VALUES (emp_seq.NEXTVAL, ?, ?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) { conn.setAutoCommit(false);
for (Employee emp : employees) { pstmt.setString(1, emp.getFirstName()); pstmt.setString(2, emp.getLastName()); pstmt.setString(3, emp.getEmail()); pstmt.setBigDecimal(4, emp.getSalary()); pstmt.setInt(5, emp.getDepartmentId()); pstmt.addBatch(); }
int[] results = pstmt.executeBatch(); conn.commit();
System.out.println("Inserted " + results.length + " employees"); } catch (SQLException e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(true); } }
public Employee getEmployee(Connection conn, int employeeId) throws SQLException {
String sql = "SELECT * FROM employees WHERE employee_id = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, employeeId);
try (ResultSet rs = pstmt.executeQuery()) { if (rs.next()) { return new Employee( rs.getInt("employee_id"), rs.getString("first_name"), rs.getString("last_name"), rs.getString("email"), rs.getBigDecimal("salary"), rs.getInt("department_id") ); } } } return null; }}Calling Stored Procedures
import java.sql.*;
public class StoredProcedureExample {
public void callGiveRaise(Connection conn, int employeeId, double percent) throws SQLException {
String sql = "{call give_raise(?, ?, ?, ?)}";
try (CallableStatement cstmt = conn.prepareCall(sql)) { // Set IN parameters cstmt.setInt(1, employeeId); cstmt.setDouble(2, percent);
// Register OUT parameters cstmt.registerOutParameter(3, Types.NUMERIC); // new_salary cstmt.registerOutParameter(4, Types.VARCHAR); // status
// Execute cstmt.execute();
// Get OUT values double newSalary = cstmt.getDouble(3); String status = cstmt.getString(4);
System.out.printf("New salary: $%.2f, Status: %s%n", newSalary, status); } }
public double callCalculateBonus(Connection conn, int employeeId) throws SQLException {
String sql = "{ ? = call calculate_bonus(?) }";
try (CallableStatement cstmt = conn.prepareCall(sql)) { cstmt.registerOutParameter(1, Types.NUMERIC); cstmt.setInt(2, employeeId); cstmt.execute(); return cstmt.getDouble(1); } }}Connection Pooling with HikariCP
import com.zaxxer.hikari.HikariConfig;import com.zaxxer.hikari.HikariDataSource;import java.sql.*;
public class ConnectionPoolExample {
private static HikariDataSource dataSource;
static { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:oracle:thin:@//localhost:1521/heliosdb"); config.setUsername("admin"); config.setPassword("password");
// Pool settings config.setMinimumIdle(5); config.setMaximumPoolSize(20); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000);
// Oracle-specific properties config.addDataSourceProperty("oracle.jdbc.implicitStatementCacheSize", "20"); config.addDataSourceProperty("oracle.jdbc.FAN.enabled", "false");
// Validation config.setConnectionTestQuery("SELECT 1 FROM DUAL");
dataSource = new HikariDataSource(config); }
public static Connection getConnection() throws SQLException { return dataSource.getConnection(); }
public static void close() { if (dataSource != null) { dataSource.close(); } }}OCI Examples
C OCI Connection
#include <oci.h>#include <stdio.h>#include <stdlib.h>#include <string.h>
void check_error(sword status, OCIError *errhp) { text errbuf[512]; sb4 errcode;
if (status != OCI_SUCCESS && status != OCI_SUCCESS_WITH_INFO) { OCIErrorGet(errhp, 1, NULL, &errcode, errbuf, sizeof(errbuf), OCI_HTYPE_ERROR); printf("Error: %s\n", errbuf); exit(1); }}
int main() { OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; OCIServer *srvhp; OCISession *authp; OCIStmt *stmthp; OCIDefine *defnp = NULL;
sword status;
// Connection parameters const char *username = "admin"; const char *password = "password"; const char *dbname = "//localhost:1521/heliosdb";
// Initialize OCI environment status = OCIEnvCreate(&envhp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL); if (status != OCI_SUCCESS) { printf("OCIEnvCreate failed\n"); return 1; }
// Allocate error handle OCIHandleAlloc(envhp, (void **)&errhp, OCI_HTYPE_ERROR, 0, NULL);
// Allocate server handle OCIHandleAlloc(envhp, (void **)&srvhp, OCI_HTYPE_SERVER, 0, NULL);
// Attach to server status = OCIServerAttach(srvhp, errhp, (text *)dbname, strlen(dbname), OCI_DEFAULT); check_error(status, errhp);
// Allocate service context OCIHandleAlloc(envhp, (void **)&svchp, OCI_HTYPE_SVCCTX, 0, NULL); OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, srvhp, 0, OCI_ATTR_SERVER, errhp);
// Allocate session handle OCIHandleAlloc(envhp, (void **)&authp, OCI_HTYPE_SESSION, 0, NULL); OCIAttrSet(authp, OCI_HTYPE_SESSION, (void *)username, strlen(username), OCI_ATTR_USERNAME, errhp); OCIAttrSet(authp, OCI_HTYPE_SESSION, (void *)password, strlen(password), OCI_ATTR_PASSWORD, errhp);
// Begin session status = OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT); check_error(status, errhp);
OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, authp, 0, OCI_ATTR_SESSION, errhp);
printf("Connected to HeliosDB successfully!\n");
// Allocate statement handle OCIHandleAlloc(envhp, (void **)&stmthp, OCI_HTYPE_STMT, 0, NULL);
// Prepare and execute query const char *sql = "SELECT employee_id, first_name FROM employees WHERE ROWNUM <= 5"; status = OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT); check_error(status, errhp);
// Define output variables int emp_id; char first_name[50];
OCIDefineByPos(stmthp, &defnp, errhp, 1, &emp_id, sizeof(emp_id), SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT); OCIDefineByPos(stmthp, &defnp, errhp, 2, first_name, sizeof(first_name), SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT);
// Execute status = OCIStmtExecute(svchp, stmthp, errhp, 0, 0, NULL, NULL, OCI_DEFAULT); check_error(status, errhp);
// Fetch results printf("\nEmployees:\n"); while ((status = OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)) == OCI_SUCCESS) { printf(" %d: %s\n", emp_id, first_name); }
// Cleanup OCISessionEnd(svchp, errhp, authp, OCI_DEFAULT); OCIServerDetach(srvhp, errhp, OCI_DEFAULT); OCIHandleFree(stmthp, OCI_HTYPE_STMT); OCIHandleFree(authp, OCI_HTYPE_SESSION); OCIHandleFree(svchp, OCI_HTYPE_SVCCTX); OCIHandleFree(srvhp, OCI_HTYPE_SERVER); OCIHandleFree(errhp, OCI_HTYPE_ERROR); OCIHandleFree(envhp, OCI_HTYPE_ENV);
return 0;}OCI Connection Pool (CPOOL)
#include <oci.h>
int main() { OCIEnv *envhp; OCICPool *poolhp; OCIError *errhp; text *poolName; sb4 poolNameLen;
const char *username = "admin"; const char *password = "password"; const char *dbname = "//localhost:1521/heliosdb";
// Initialize OCIEnvCreate(&envhp, OCI_THREADED, NULL, NULL, NULL, NULL, 0, NULL); OCIHandleAlloc(envhp, (void **)&errhp, OCI_HTYPE_ERROR, 0, NULL); OCIHandleAlloc(envhp, (void **)&poolhp, OCI_HTYPE_CPOOL, 0, NULL);
// Create connection pool sword status = OCIConnectionPoolCreate( envhp, errhp, poolhp, &poolName, &poolNameLen, (text *)dbname, strlen(dbname), 2, // min connections 10, // max connections 1, // increment (text *)username, strlen(username), (text *)password, strlen(password), OCI_DEFAULT );
if (status == OCI_SUCCESS) { printf("Connection pool created: %.*s\n", poolNameLen, poolName);
// Get connection from pool OCISvcCtx *svchp; OCIHandleAlloc(envhp, (void **)&svchp, OCI_HTYPE_SVCCTX, 0, NULL);
status = OCILogon2( envhp, errhp, &svchp, (text *)username, strlen(username), (text *)password, strlen(password), poolName, poolNameLen, OCI_CPOOL );
if (status == OCI_SUCCESS) { printf("Got connection from pool\n"); // Use connection... OCILogoff(svchp, errhp); } }
// Destroy pool OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT);
return 0;}Python Examples
Basic oracledb Connection
import oracledb
# Connect to HeliosDBconnection = oracledb.connect( user="admin", password="password", dsn="localhost:1521/heliosdb")
print(f"Connected to: {connection.version}")
# Simple querywith connection.cursor() as cursor: cursor.execute(""" SELECT employee_id, first_name, last_name, salary FROM employees WHERE department_id = :dept_id ORDER BY salary DESC """, dept_id=10)
for row in cursor: print(f"{row[0]}: {row[1]} {row[2]} - ${row[3]:,.2f}")
connection.close()Connection Pool
import oracledb
# Create connection poolpool = oracledb.create_pool( user="admin", password="password", dsn="localhost:1521/heliosdb", min=2, max=10, increment=1, getmode=oracledb.POOL_GETMODE_WAIT, timeout=60)
print(f"Pool opened: {pool.opened} connections")
# Use poolwith pool.acquire() as connection: with connection.cursor() as cursor: cursor.execute("SELECT COUNT(*) FROM employees") count = cursor.fetchone()[0] print(f"Total employees: {count}")
# Pool statisticsprint(f"Pool busy: {pool.busy}")print(f"Pool open: {pool.opened}")
pool.close()Calling PL/SQL
import oracledb
connection = oracledb.connect( user="admin", password="password", dsn="localhost:1521/heliosdb")
with connection.cursor() as cursor: # Call procedure with OUT parameters new_salary = cursor.var(oracledb.NUMBER) status = cursor.var(oracledb.STRING, 200)
cursor.callproc('give_raise', [100, 10, new_salary, status])
print(f"New salary: ${new_salary.getvalue():,.2f}") print(f"Status: {status.getvalue()}")
# Call function bonus = cursor.callfunc('calculate_bonus', oracledb.NUMBER, [100]) print(f"Bonus: ${bonus:,.2f}")
# Execute anonymous block cursor.execute(""" BEGIN DBMS_OUTPUT.ENABLE(10000); DBMS_OUTPUT.PUT_LINE('Hello from PL/SQL'); FOR emp IN (SELECT first_name FROM employees WHERE ROWNUM <= 3) LOOP DBMS_OUTPUT.PUT_LINE(' ' || emp.first_name); END LOOP; END; """)
# Get DBMS_OUTPUT lines = cursor.var(oracledb.STRING, arraysize=100) num_lines = cursor.var(oracledb.NUMBER) num_lines.setvalue(0, 100)
cursor.callproc('DBMS_OUTPUT.GET_LINES', [lines, num_lines])
for i in range(int(num_lines.getvalue())): if lines.getvalue()[i]: print(lines.getvalue()[i])
connection.close()Node.js Examples
Basic Connection
const oracledb = require('oracledb');
async function run() { let connection;
try { connection = await oracledb.getConnection({ user: 'admin', password: 'password', connectString: 'localhost:1521/heliosdb' });
console.log('Connected to HeliosDB');
// Simple query const result = await connection.execute( `SELECT employee_id, first_name, last_name, salary FROM employees WHERE department_id = :deptId ORDER BY salary DESC`, { deptId: 10 }, { outFormat: oracledb.OUT_FORMAT_OBJECT } );
console.log('Employees:'); for (const row of result.rows) { console.log(` ${row.EMPLOYEE_ID}: ${row.FIRST_NAME} ${row.LAST_NAME} - $${row.SALARY}`); }
} finally { if (connection) { await connection.close(); } }}
run().catch(console.error);Connection Pool
const oracledb = require('oracledb');
async function init() { await oracledb.createPool({ user: 'admin', password: 'password', connectString: 'localhost:1521/heliosdb', poolMin: 2, poolMax: 10, poolIncrement: 1, poolTimeout: 60, poolAlias: 'hrpool' });
console.log('Pool created');}
async function getEmployeeCount() { const connection = await oracledb.getConnection('hrpool');
try { const result = await connection.execute( 'SELECT COUNT(*) as count FROM employees' ); return result.rows[0][0]; } finally { await connection.close(); }}
async function close() { await oracledb.getPool('hrpool').close(0);}
// Usageinit() .then(() => getEmployeeCount()) .then(count => console.log(`Total employees: ${count}`)) .then(() => close()) .catch(console.error);Error Handling Examples
PL/SQL Exception Handling
DECLARE v_salary NUMBER; e_employee_not_found EXCEPTION; PRAGMA EXCEPTION_INIT(e_employee_not_found, -20001);BEGIN BEGIN SELECT salary INTO v_salary FROM employees WHERE employee_id = 9999; -- Non-existent
EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20001, 'Employee not found'); END;
EXCEPTION WHEN e_employee_not_found THEN DBMS_OUTPUT.PUT_LINE('Custom error: ' || SQLERRM); DBMS_OUTPUT.PUT_LINE('Backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Unexpected error: ' || SQLCODE); DBMS_OUTPUT.PUT_LINE('Message: ' || SQLERRM); DBMS_OUTPUT.PUT_LINE('Stack: ' || DBMS_UTILITY.FORMAT_ERROR_STACK); RAISE;END;/JDBC Exception Handling
import java.sql.*;
public class ErrorHandlingExample {
public void handleOracleError(Connection conn) { try { CallableStatement cstmt = conn.prepareCall( "{call procedure_that_may_fail(?)}" ); cstmt.setInt(1, 100); cstmt.execute();
} catch (SQLException e) { int errorCode = e.getErrorCode(); String sqlState = e.getSQLState(); String message = e.getMessage();
System.err.printf("Oracle Error %d (SQLSTATE %s): %s%n", errorCode, sqlState, message);
// Handle specific Oracle errors switch (errorCode) { case 1: // ORA-00001: unique constraint violated System.err.println("Duplicate key detected"); break; case 1017: // ORA-01017: invalid username/password System.err.println("Authentication failed"); break; case 1400: // ORA-01400: cannot insert NULL System.err.println("Required field is null"); break; case 2291: // ORA-02291: integrity constraint violated System.err.println("Foreign key violation"); break; default: if (errorCode >= 20000 && errorCode <= 20999) { System.err.println("Application error: " + message); } else { System.err.println("Unexpected database error"); } } } }}Related Documentation
- README.md - Protocol overview and compatibility
- CONFIGURATION.md - Server and client configuration
- COMPATIBILITY.md - Feature compatibility matrix
- PLSQL_SUPPORT.md - PL/SQL support details
Last Updated: January 2026 Examples Version: HeliosDB 7.0+