DML – Data Manipulation Language: INSERT, UPDATE, DELETE, MERGE

Subject: Information Technology – Database Systems School level: 11th grade – HTL Informatik Requirements: DQL – SELECT, joins, subqueries, SCOTT schema Author: HTL Pinkafeld – IF/IT



1. Overview of DML and transactions

1.1 What is DML?

DML (Data Manipulation Language) includes all SQL statements that manipulate data in tables:

DML-Anweisungen:
├── INSERT  → neue Zeilen hinzufügen
├── UPDATE  → bestehende Zeilen ändern
├── DELETE  → Zeilen entfernen
└── MERGE   → einfügen ODER aktualisieren (Upsert)

Unlike DDL (CREATE, ALTER, DROP), DML works on the data - not the structure.

1.2 DML and Transactions

Each DML statement automatically starts a transaction (if none is already active). Changes are initially only visible for your own session and are only saved permanently by COMMIT or undone by ROLLBACK:

DML-Anweisung
      │
      ▼
Change in the buffer (only visible for your own session)
      │
├── COMMIT → saved permanently, visible to everyone
└── ROLLBACKall changes since the last COMMIT are rolled back

Important in Oracle: DDL statements (CREATE, ALTER, DROP) always execute an implicit COMMIT - all open DML changes are saved permanently!


2. INSERT – insert rows

-- Complete syntax with column list
INSERT INTO EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES         (8000, 'MUSTER', 'CLERK', 7782,
                TO_DATE('15.09.2024', 'DD.MM.YYYY'),
                1500, NULL, 10);

-- Fill only certain columns (remaining ones get NULL or DEFAULT)
INSERT INTO EMP (EMPNO, ENAME, JOB, SAL, DEPTNO)
VALUES         (8001, 'HUBER', 'ANALYST', 3200, 20);
-- MGR, HIREDATE, COMM erhalten NULL

2.2 INSERT without column list

-- Without column list: Order must correspond exactly to the table definition
-- All columns must be specified!
INSERT INTO DEPT
VALUES (50, 'IT', 'WIEN');

Recommendation: Always specify the column list. Without a column list, the statement breaks as soon as someone adds a column to the table.

2.3 Different value types

-- Zahlen: direkt angeben
INSERT INTO EMP (EMPNO, SAL) VALUES (8002, 2500);

-- Strings: single quotes
INSERT INTO EMP (EMPNO, ENAME) VALUES (8003, 'SCHULZ');

-- Date: TO_DATE or date literal
INSERT INTO EMP (EMPNO, HIREDATE)
VALUES (8004, TO_DATE('01.01.2025', 'DD.MM.YYYY'));

-- Insert NULL explicitly
INSERT INTO EMP (EMPNO, ENAME, COMM)
VALUES (8005, 'NOVAK', NULL);

-- SYSDATE for current date
INSERT INTO EMP (EMPNO, ENAME, HIREDATE)
VALUES (8006, 'WAGNER', SYSDATE);

2.4 INSERT with DEFAULT

-- Wenn eine Spalte einen DEFAULT-Wert hat, kann DEFAULT verwendet werden
CREATE TABLE PROTOKOLL (
    ID        NUMBER         PRIMARY KEY,
    AKTION    VARCHAR2(100),
    ZEITSTEMPEL DATE          DEFAULT SYSDATE,
    BENUTZER  VARCHAR2(30)   DEFAULT USER
);

INSERT INTO PROTOKOLL (ID, AKTION)
VALUES (1, 'Login');
-- ZEITSTEMPEL und BENUTZER erhalten ihre DEFAULT-Werte

2.5 Multiple lines at the same time (INSERT ALL)

-- INSERT ALL: multiple lines in one statement
INSERT ALL
    INTO DEPT VALUES (50, 'IT',        'WIEN')
    INTO DEPT VALUES (60, 'MARKETING', 'GRAZ')
    INTO DEPT VALUES (70, 'SUPPORT',   'LINZ')
SELECT * FROM DUAL;   -- Pflicht: SELECT-Klausel am Ende

3. INSERT with subquery

3.1 Copy data from another table

-- Create backup table
CREATE TABLE EMP_BACKUP AS SELECT * FROM EMP WHERE 1=2;
-- (empty table with the same structure – 1=2 is always wrong)

-- Daten hineinkopieren
INSERT INTO EMP_BACKUP
SELECT * FROM EMP;

-- Only certain employees copy
INSERT INTO EMP_BACKUP (EMPNO, ENAME, JOB, SAL, DEPTNO)
SELECT EMPNO, ENAME, JOB, SAL, DEPTNO
FROM   EMP
WHERE  DEPTNO = 20;

3.2 INSERT with calculated values

-- Fill new table for annual salaries
CREATE TABLE JAHRESGEHALT (
    EMPNO       NUMBER(4),
    ENAME       VARCHAR2(10),
    JAHRESBETRAG NUMBER(10,2)
);

INSERT INTO JAHRESGEHALT (EMPNO, ENAME, JAHRESBETRAG)
SELECT EMPNO,
       ENAME,
       SAL * 12 + NVL(COMM, 0) * 12
FROM   EMP;

COMMIT;

3.3 INSERT ALL with conditions

-- Insert employees into different tables depending on their salary
INSERT ALL
    WHEN SAL < 1500 THEN
        INTO EMP_NIEDRIG VALUES (EMPNO, ENAME, SAL)
    WHEN SAL BETWEEN 1500 AND 3000 THEN
        INTO EMP_MITTEL VALUES (EMPNO, ENAME, SAL)
    WHEN SAL > 3000 THEN
        INTO EMP_HOCH VALUES (EMPNO, ENAME, SAL)
SELECT EMPNO, ENAME, SAL FROM EMP;

4. UPDATE – Update rows

4.1 Basic syntax

UPDATE tabellenname
SET    spalte1 = wert1,
       spalte2 = wert2,
       ...
WHERE  bedingung;

⚠️ Warning: An UPDATE without WHERE updates all rows of the table!

4.2 Simple UPDATE examples

-- Increase the salary of a specific employee
UPDATE EMP
SET    SAL = 3500
WHERE  EMPNO = 7369;

-- Change multiple columns at once
UPDATE EMP
SET    SAL     = 2000,
       JOB     = 'ANALYST',
       DEPTNO  = 20
WHERE  EMPNO = 7900;

-- Change relative to current value (10% salary increase for department 20)
UPDATE EMP
SET    SAL = SAL * 1.1
WHERE  DEPTNO = 20;

-- All salesmen receive a commission of 10% of their salary (if none already)
UPDATE EMP
SET    COMM = SAL * 0.1
WHERE  JOB = 'SALESMAN'
  AND  COMM IS NULL;

4.3 UPDATE multiple columns with expressions

-- Update date and profession at the same time
UPDATE EMP
SET    HIREDATE = SYSDATE,
       JOB      = 'MANAGER',
       MGR      = 7839
WHERE  ENAME = 'MUSTER';

-- Calculated value: Round salary to nearest 100
UPDATE EMP
SET    SAL = CEIL(SAL / 100) * 100
WHERE  DEPTNO = 30;

4.4 UPDATE without WHERE – All lines

-- All employees: Adjust salaries to compensate for inflation
UPDATE EMP
SET    SAL = ROUND(SAL * 1.03, 2);

-- Check before COMMIT:
SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY EMPNO;

COMMIT;

5. UPDATE with subquery

5.1 Take value from another table

-- Place SCOTT's department at the DALLAS location
UPDATE EMP
SET    DEPTNO = (SELECT DEPTNO
                 FROM   DEPT
                 WHERE  LOC = 'DALLAS')
WHERE  ENAME = 'SCOTT';

-- Set salary to the average for your own department
-- (korrelierte Subquery im SET!)
UPDATE EMP e
SET    SAL = (SELECT ROUND(AVG(SAL), 0)
              FROM   EMP i
              WHERE  i.DEPTNO = e.DEPTNO)
WHERE  JOB = 'CLERK';

5.2 Multiple columns with subquery

-- Set multiple columns from a subquery at the same time
UPDATE EMP
SET    (SAL, COMM) = (SELECT SAL * 1.1, COMM * 1.2
                      FROM   EMP
                      WHERE  ENAME = 'ALLEN')
WHERE  ENAME = 'WARD';

-- Alternativ mit einzelnen Subqueries
UPDATE EMP
SET    SAL  = (SELECT SAL  * 1.1 FROM EMP WHERE ENAME = 'ALLEN'),
       COMM = (SELECT COMM * 1.2 FROM EMP WHERE ENAME = 'ALLEN')
WHERE  ENAME = 'WARD';

5.3 UPDATE with EXISTS

-- Only update employees whose department is in CHICAGO
UPDATE EMP e
SET    SAL = SAL * 1.05
WHERE  EXISTS (SELECT 1
               FROM   DEPT d
               WHERE  d.DEPTNO = e.DEPTNO
                 AND  d.LOC = 'CHICAGO');

6. DELETE – delete lines

6.1 Basic syntax

DELETE FROM tabellenname
WHERE  bedingung;

⚠️ Warning: A DELETE without WHERE deletes all rows of the table! The structure remains intact.

6.2 Simple DELETE examples

-- Delete a specific employee
DELETE FROM EMP
WHERE  EMPNO = 8000;

-- Delete all employees in a department
DELETE FROM EMP
WHERE  DEPTNO = 40;

-- Delete employees who were hired before 1982
DELETE FROM EMP
WHERE  HIREDATE < TO_DATE('01.01.1982', 'DD.MM.YYYY');

-- Delete all employees without commission (COMM is NULL)
DELETE FROM EMP
WHERE  COMM IS NULL;

6.3 DELETE with subquery

-- Delete all employees in departments that are in NEW YORK
DELETE FROM EMP
WHERE  DEPTNO IN (SELECT DEPTNO
                  FROM   DEPT
                  WHERE  LOC = 'NEW YORK');

-- Delete employees whose salary is below average
DELETE FROM EMP
WHERE  SAL < (SELECT AVG(SAL) FROM EMP);

-- With EXISTS: Delete employees who are not assigned to a department
DELETE FROM EMP e
WHERE  NOT EXISTS (SELECT 1
                   FROM   DEPT d
                   WHERE  d.DEPTNO = e.DEPTNO);

6.4 Sequence of deletion with foreign keys

-- ERROR: Cannot delete department while employees are referencing it
DELETE FROM DEPT WHERE DEPTNO = 20;
-- ORA-02292: integrity constraint violated - child record found

-- CORRECT: First delete employees, then department
DELETE FROM EMP  WHERE DEPTNO = 20;
DELETE FROM DEPT WHERE DEPTNO = 20;
COMMIT;

7. TRUNCATE – Empty table

7.1 TRUNCATE vs. DELETE

-- Remove all rows from a table
TRUNCATE TABLE EMP_BACKUP;
Characteristic DELETE (without WHERE) TRUNCATE
Deletes all lines
ROLLBACK possible ❌ (DDL!)
Triggers are fired
speed Slower Very fast
Free up memory No Yes
WHERE possible
Belongs to DML DDL

7.2 When to use TRUNCATE?

-- Good use cases for TRUNCATE:
-- 1. Flush staging tables before reloading
TRUNCATE TABLE STAGE_IMPORT;

-- 2. Remove test data before refilling
TRUNCATE TABLE TEST_DATEN;

-- ATTENTION: TRUNCATE cannot be undone!
-- Check before: SELECT COUNT(*) FROM table;

8. Transaction Control – COMMIT and ROLLBACK

8.1 COMMIT – save changes permanently

-- Ablauf einer typischen Transaktion:

-- 1. Make changes
INSERT INTO EMP (EMPNO, ENAME, JOB, SAL, DEPTNO)
VALUES         (8010, 'BAUER', 'CLERK', 1400, 30);

UPDATE EMP SET SAL = 5500 WHERE EMPNO = 7839;

-- 2. Check result
SELECT EMPNO, ENAME, SAL FROM EMP WHERE EMPNO IN (8010, 7839);

-- 3. Save permanently
COMMIT;
-- Now visible to all other users and can no longer be undone

8.2 ROLLBACK – Undo changes

-- make changes
DELETE FROM EMP WHERE DEPTNO = 20;

-- Oops! Wrong command
-- Check:
SELECT COUNT(*) FROM EMP;   -- 9 instead of 14

-- Undo (as long as no COMMIT!)
ROLLBACK;

-- Check:
SELECT COUNT(*) FROM EMP;   -- back to 14

8.3 Automatic COMMIT and ROLLBACK

-- Implizites COMMIT tritt auf bei:
-- 1. DDL-Anweisung (CREATE, ALTER, DROP, TRUNCATE)
-- 2. Normales Beenden der Session (EXIT in SQL*Plus)

-- Implizites ROLLBACK tritt auf bei:
-- 1. Absturz / Verbindungsabbruch
-- 2. Session termination without COMMIT (in some tools)

8.4 Read Consistency

-- Oracle Multiversion Concurrency Control (MVCC):
-- Andere Benutzer sehen IMMER den letzten COMMIT-Stand
-- Your own session sees your uncommitted changes

-- Session A:                    Session B:
UPDATE EMP SET SAL=999            SELECT SAL FROM EMP
WHERE EMPNO=7839;                 WHERE EMPNO=7839;
                                  -- Sieht noch 5000 (vor Update)
COMMIT;
                                  SELECT SAL FROM EMP
                                  WHERE EMPNO=7839;
                                  -- Sieht jetzt 999

9. SAVEPOINT – partial withdrawal

9.1 Set savepoints

With SAVEPOINT intermediate points can be set within a transaction. A ROLLBACK TO savepoint only undoes the changes since the savepoint:

-- Transaktion mit mehreren Schritten

-- Step 1: New department
INSERT INTO DEPT VALUES (50, 'ENTWICKLUNG', 'WIEN');
SAVEPOINT nach_dept;

-- Step 2: Add employees
INSERT INTO EMP (EMPNO, ENAME, JOB, SAL, DEPTNO)
VALUES (8020, 'KLEIN', 'ANALYST', 3000, 50);
SAVEPOINT nach_emp1;

INSERT INTO EMP (EMPNO, ENAME, JOB, SAL, DEPTNO)
VALUES (8021, 'GROSS', 'CLERK', 1200, 50);
SAVEPOINT nach_emp2;

-- Kontrollabfrage
SELECT * FROM EMP WHERE DEPTNO = 50;

-- Just undo last INSERT
ROLLBACK TO nach_emp1;
-- emp2 (LARGE) has been deleted, emp1 (SMALL) and DEPT 50 remain

-- Check
SELECT * FROM EMP WHERE DEPTNO = 50;   -- just SMALL

-- Confirm everything
COMMIT;

9.2 Savepoint hierarchy

COMMIT / Start
    │
    ├── DML 1
    ├── SAVEPOINT A
    ├── DML 2
    ├── SAVEPOINT B
    ├── DML 3
    └── SAVEPOINT C

ROLLBACK TO B → DML 3 and SAVEPOINT C are undone
ROLLBACK TO A → DML 2, DML 3, SAVEPOINT B and C undone
ROLLBACK → Undo everything since the last COMMIT
COMMIT → Save everything permanently (savepoints deleted)

10. MERGE – Upsert

10.1 What is MERGE?

MERGE combines INSERT and UPDATE in a single statement: if a row exists in the target table, it is updated - if not, it is inserted. This pattern is also called Upsert (Update + Insert).

10.2 Basic syntax

MERGE INTO zieltabelle z
USING quelltabelle   q ON (z.schluessel = q.schluessel)
WHEN MATCHED THEN
    UPDATE SET z.spalte1 = q.spalte1,
               z.spalte2 = q.spalte2
WHEN NOT MATCHED THEN
    INSERT (spalte1, spalte2, ...)
    VALUES (q.spalte1, q.spalte2, ...);

10.3 Practical example

-- Staging table with new/updated employee data
CREATE TABLE EMP_UPDATES (
    EMPNO   NUMBER(4),
    ENAME   VARCHAR2(10),
    SAL     NUMBER(7,2),
    DEPTNO  NUMBER(2)
);

-- Neue Daten simulieren:
-- 7369 = existing (SAL changed), 9001 = new
INSERT INTO EMP_UPDATES VALUES (7369, 'SMITH',  999, 20);
INSERT INTO EMP_UPDATES VALUES (9001, 'NEUMANN', 2500, 30);

-- MERGE: update or insert
MERGE INTO EMP z
USING EMP_UPDATES q ON (z.EMPNO = q.EMPNO)
WHEN MATCHED THEN
    UPDATE SET z.SAL    = q.SAL,
               z.DEPTNO = q.DEPTNO
WHEN NOT MATCHED THEN
    INSERT (EMPNO, ENAME, SAL, DEPTNO)
    VALUES (q.EMPNO, q.ENAME, q.SAL, q.DEPTNO);

-- Check result:
SELECT * FROM EMP WHERE EMPNO IN (7369, 9001);
-- 7369/SMITH hat jetzt SAL=999
-- 9001/NEUMANN has been added

COMMIT;

10.4 MERGE with DELETE

-- MERGE can also delete rows (Oracle extension)
MERGE INTO EMP z
USING EMP_UPDATES q ON (z.EMPNO = q.EMPNO)
WHEN MATCHED THEN
    UPDATE SET z.SAL = q.SAL
    DELETE WHERE z.SAL < 1000   -- Delete line after update if SAL < 1000
WHEN NOT MATCHED THEN
    INSERT (EMPNO, ENAME, SAL, DEPTNO)
    VALUES (q.EMPNO, q.ENAME, q.SAL, q.DEPTNO);

11. Constraints and DML errors

11.1 Common Constraint Errors

-- ORA-00001: UNIQUE / PRIMARY KEY verletzt
INSERT INTO DEPT VALUES (10, 'TEST', 'WIEN');
-- DEPTNO 10 existiert bereits!

-- ORA-02291: Foreign key – parent key not found
INSERT INTO EMP (EMPNO, ENAME, DEPTNO) VALUES (9999, 'TEST', 99);
-- Department 99 does not exist!

-- ORA-02292: Foreign key – child record exists
DELETE FROM DEPT WHERE DEPTNO = 20;
-- Still employees in department 20!

-- ORA-01400: NOT NULL verletzt
INSERT INTO EMP (EMPNO, ENAME) VALUES (NULL, 'TEST');
-- EMPNO ist NOT NULL!

-- ORA-02290: CHECK Constraint verletzt
-- (wenn z.B. CHECK (SAL > 0) definiert)
UPDATE EMP SET SAL = -100 WHERE EMPNO = 7369;

11.2 Catch and analyze errors

-- Show error number and error message in SQL*Plus
-- Outputs automatically after an error

-- Important ORA error codes for DML:
-- ORA-00001  Unique constraint violated
-- ORA-01400  Cannot insert NULL
-- ORA-02290  Check constraint violated
-- ORA-02291  Parent key not found (FK-Insert)
-- ORA-02292  Child record found (FK-Delete)
-- ORA-01427  Single-row subquery returns more than one row
-- ORA-01722  Invalid number (wrong type conversion)
-- ORA-01843 Not a valid month (incorrect date format)

11.3 DML Safety Net: Check before COMMIT

-- Good practice: Check the changes before each COMMIT

-- 1. Make changes
UPDATE EMP SET SAL = SAL * 1.15 WHERE DEPTNO = 30;

-- 2. Check number of affected rows (SQL%ROWCOUNT in PL/SQL)
-- In SQL Developer: Statuszeile zeigt "6 rows updated"

-- 3. Check data
SELECT EMPNO, ENAME, SAL FROM EMP WHERE DEPTNO = 30;

-- 4. Only then commit or uncommit
COMMIT;    -- or ROLLBACK;

12. Summary and outlook

Overview of DML statements

-- INSERT: insert new line
INSERT INTO tabelle (col1, col2) VALUES (val1, val2);
INSERT INTO tabelle (col1, col2) SELECT col1, col2 FROM quelle;

-- UPDATE: change existing lines
UPDATE tabelle SET col1 = val1, col2 = val2 WHERE bedingung;
UPDATE tabelle SET col1 = (SELECT ... FROM ...) WHERE bedingung;

-- DELETE: Remove lines
DELETE FROM tabelle WHERE bedingung;
DELETE FROM tabelle WHERE col IN (SELECT ... FROM ...);

-- TRUNCATE: remove all lines (DDL, no ROLLBACK!)
TRUNCATE TABLE tabelle;

-- MERGE: insert or update
MERGE INTO ziel z
USING quelle q ON (z.id = q.id)
WHEN MATCHED     THEN UPDATE SET z.col = q.col
WHEN NOT MATCHED THEN INSERT (id, col) VALUES (q.id, q.col);

-- Transaction control
COMMIT;                   -- save permanently
ROLLBACK;                 -- undo everything since the last COMMIT
SAVEPOINT name;           -- set a savepoint
ROLLBACK TO name;         -- back to the save point

Golden Rules for DML

Immer WHERE bei UPDATE und DELETE prüfen
  → SELECT mit gleicher WHERE-Bedingung vorher ausführen!

Vor COMMIT Ergebnis kontrollieren
→ Check number of affected lines and content

ROLLBACK is only possible before the next COMMIT
  → Kein ROLLBACK nach DDL-Anweisung!

Pay attention to the order of FK dependencies
→ Delete child tables first, then parent tables

TRUNCATE ist unwiderruflich
→ Always COUNT(*) in front of it, check backup beforehand

Bei NOT IN mit Subquery NULL ausschließen
  → WHERE spalte NOT IN (SELECT ... WHERE ... IS NOT NULL)

Checklist

INSERT mit und ohne Spaltenliste
INSERT mit Subquery (Daten kopieren)
UPDATE mit WHERE und Subquery
DELETE mit WHERE und Fremdschlüssel-Reihenfolge
TRUNCATE vs. DELETE kennen
COMMIT und ROLLBACK anwenden
SAVEPOINT setzen und ROLLBACK TO verwenden
MERGE: Syntax und Anwendungsfall erklären
Constraint-Fehlermeldungen lesen und beheben
DML safety net: check before COMMIT

Typical exam tasks

-- 1. Insert new department and employees
INSERT INTO DEPT VALUES (50, 'ENTWICKLUNG', 'WIEN');
INSERT INTO EMP (EMPNO, ENAME, JOB, SAL, DEPTNO, HIREDATE)
VALUES (9000, 'TESTER', 'ANALYST', 3500, 50, SYSDATE);
COMMIT;

-- 2. All clerks in department 20 receive 15% more salary
UPDATE EMP SET SAL = ROUND(SAL * 1.15, 0)
WHERE  JOB = 'CLERK' AND DEPTNO = 20;
SELECT ENAME, SAL FROM EMP WHERE JOB = 'CLERK' AND DEPTNO = 20;
COMMIT;

-- 3. Delete all employees whose salary is below average
DELETE FROM EMP
WHERE SAL < (SELECT AVG(SAL) FROM EMP);
ROLLBACK;   -- Undo for further exercises

-- 4. Set salary to department average (correlated subquery)
UPDATE EMP e
SET    SAL = (SELECT ROUND(AVG(SAL), 0) FROM EMP i WHERE i.DEPTNO = e.DEPTNO)
WHERE  JOB = 'CLERK';
SELECT ENAME, SAL, DEPTNO FROM EMP WHERE JOB = 'CLERK';
ROLLBACK;

-- 5. MERGE: Gehaltstabelle mit aktuellen Werten synchronisieren
MERGE INTO JAHRESGEHALT j
USING (SELECT EMPNO, ENAME, SAL*12 + NVL(COMM,0)*12 AS jahresbetrag
       FROM EMP) q
ON (j.EMPNO = q.EMPNO)
WHEN MATCHED THEN
    UPDATE SET j.JAHRESBETRAG = q.jahresbetrag
WHEN NOT MATCHED THEN
    INSERT (EMPNO, ENAME, JAHRESBETRAG)
    VALUES (q.EMPNO, q.ENAME, q.jahresbetrag);
COMMIT;

Outlook: Next topics


HTL Pinkafeld – IF/IT | Oracle SQL | 11th grade

Previous TopicSubqueries Next TopicDDL & Data Dictionary