- Introduction
- Page Goals (learn in ~3 minutes)
- Start with the Basics: How to Think About insert oracle
- Safe Input by Data Type (avoid implicit conversion)
- Two Ways to Auto-Number: Choosing Between IDENTITY and SEQUENCE
- Get the Generated Value Immediately: The RETURNING Clause
- Common Errors and Fixes (quick reference)
- Transaction Basics (commit = confirm / rollback = cancel)
- Step-by-Step Execution (verified on 19c / Oracle Linux 7.9)
- Practical Tips (what to watch for)
- INSERT ... SELECT will be covered in a separate article
- Summary
Introduction
The basic operation for adding a new row (record) to a database is oracle insert. This article explains the correct way to use insert oracle with plain language and “copy-and-run” examples. We verified everything on Oracle Database 19c, covering: creating a user → creating a table → INSERT → verification → error handling.
See here for information on creating a table.
Page Goals (learn in ~3 minutes)
- Understand the safe way to write INSERT (explicit column list).
- Write dates, timestamps, and numbers without mistakes.
- Explain the difference and proper use of IDENTITY and SEQUENCE.
- Diagnose common errors and fixes on your own.
Start with the Basics: How to Think About insert oracle
An INSERT statement specifies “which table,” “which columns,” and “what values.” To make your code resilient to future changes, always specify column names.
Example: Basic Form
-- Recommended: specify column names (safe and readable)
INSERT INTO table_name (col1, col2, ...) VALUES (val1, val2, ...);
-- Not recommended: rely on all columns in order (breaks when columns are added)
INSERT INTO table_name VALUES (val1, val2, ...);
Key Points
- Columns omitted in the INSERT list receive DEFAULT values; if no default, they become NULL.
- Omitting a
NOT NULLcolumn raises an error (ORA-01400). - For dates and times, explicitly specify formats using
TO_DATE/TO_TIMESTAMPfor safety.
Note: Omitting Column Names and Specifying NULL
- When supplying values for every column, you may omit the column list (but this is fragile if columns are added later; in practice, specifying columns is safer).
- If you want to leave a column empty, write
NULLinsideVALUES. (If you omit a column, the DEFAULT applies; if no default, it becomes NULL.)
-- Omitting the column list (provide values for all columns in table order)
INSERT INTO customers
VALUES (DEFAULT, 'Foo', 'foo@example.com', SYSDATE, 'A');
-- Explicitly insert NULL for columns (set joined_on and email to NULL)
INSERT INTO customers (name, email, joined_on, status)
VALUES ('Bar', NULL, NULL, 'A');
Text Diagram: Flow of INSERT
┌──── Client (SQL*Plus / SQLcl / App) ────┐
│ INSERT INTO T(colA,colB) VALUES(:A,:B); │
└───────────────↓─────────────────────────┘
┌──────── Oracle Server ────────┐ ┌─ Tablespace ─┐
│ ① Parse ② Constraint checks │→ │ Write rows │
│ (NOT NULL/Unique/ForeignKey)│ │ Update indexes│
└───────────────────────────────┘ └───────────────┘
Safe Input by Data Type (avoid implicit conversion)
Oracle’s implicit conversions can be surprising. Insert data using the intended type.
-- String (enclose in single quotes)
INSERT INTO t(c_vc2) VALUES ('山田太郎');
-- Date (explicit format)
INSERT INTO t(c_date) VALUES (TO_DATE('2025-08-01','YYYY-MM-DD'));
-- Timestamp (with milliseconds)
INSERT INTO t(c_ts) VALUES (
TO_TIMESTAMP('2025-08-01 10:20:30.123','YYYY-MM-DD HH24:MI:SS.FF3')
);
-- Number (no quotes)
INSERT INTO t(c_num) VALUES (12345);
Two Ways to Auto-Number: Choosing Between IDENTITY and SEQUENCE
“When you want the primary key to auto-increment,” use an IDENTITY column or a SEQUENCE. Both generate numbers, but they fit different designs and operations.
Bottom Line First (quick chooser)
┌──────────────────────┬─────────────────────────────────────────────┐
│ What you want │ Recommendation │
├──────────────────────┼─────────────────────────────────────────────┤
│ Easiest auto-number │ IDENTITY column (defined on the table) │
│ Fine-grained control │ SEQUENCE (start/increment/cache/cycle, etc.)│
│ App already uses NEXTVAL │ SEQUENCE │
└──────────────────────┴─────────────────────────────────────────────┘
IDENTITY Column (simple, great for learning)
What it is: A column property that “auto-numbers” rows. Internally, it uses a sequence-like mechanism.
Main options
GENERATED ALWAYS AS IDENTITY… DB always assigns the value (manual input is an error)GENERATED BY DEFAULT AS IDENTITY… DB assigns by default; manual override is allowed- (Advanced)
BY DEFAULT ON NULL… DB assigns only when the inserted value isNULL
Basic example
CREATE TABLE demo_customers (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
email VARCHAR2(255) UNIQUE,
joined_on DATE DEFAULT SYSDATE,
status CHAR(1) DEFAULT 'A' CHECK (status IN ('A','I'))
);
-- DB auto-assigns id
INSERT INTO demo_customers (name, email)
VALUES ('Sato Ichiro','s.ichiro@example.com');
Command execution example
SQL> CREATE TABLE demo_customers (
2 id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
3 name VARCHAR2(50) NOT NULL,
4 email VARCHAR2(255) UNIQUE,
5 joined_on DATE DEFAULT SYSDATE,
6 status CHAR(1) DEFAULT 'A' CHECK (status IN ('A','I'))
7 );
Table created.
SQL> INSERT INTO demo_customers (name, email)
2 VALUES ('Sato Ichiro','s.ichiro@example.com');
1 row created.
SQL> set lin 1000
SQL> col name for a15
SQL> col email for a25
SQL> select * from demo_customers;
ID NAME EMAIL JOINED_ON S
---------- --------------- ------------------------- --------- -
1 Sato Ichiro s.ichiro@example.com 23-AUG-25 A
FAQ
- Q: If I ROLLBACK, does the number “go back”? → No. Numbers may be gapped due to rollbacks/concurrency/failures.
- Q: Change the next starting value? → Alter the column:
ALTER TABLE demo_customers MODIFY
(id GENERATED BY DEFAULT AS IDENTITY START WITH 1000);
- Q: Can I set the value manually? → Only when using
BY DEFAULT.
Pros / Cautions
- No extra object to manage; simple.
- Expect gaps (that’s normal).
SEQUENCE (more control, production-oriented)
What it is: An independent number generator. Use NEXTVAL for the next number and CURRVAL for the most recently generated number in the session.
Create and use
-- Create
CREATE SEQUENCE demo_customers_seq START WITH 1 INCREMENT BY 1 CACHE 20 NOCYCLE;
-- Table using the sequence
CREATE TABLE demo_customers_seqver (
id NUMBER PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
created_at DATE DEFAULT SYSDATE
);
-- Use NEXTVAL on insert
INSERT INTO demo_customers_seqver (id, name)
VALUES (demo_customers_seq.NEXTVAL, 'Tanaka Hanako');
-- In the same session, CURRVAL returns the last number
SELECT demo_customers_seq.CURRVAL FROM dual;
Command execution example
SQL> CREATE SEQUENCE demo_customers_seq START WITH 1 INCREMENT BY 1 CACHE 20 NOCYCLE;
Sequence created.
SQL> CREATE TABLE demo_customers_seqver (
2 id NUMBER PRIMARY KEY,
3 name VARCHAR2(50) NOT NULL,
4 created_at DATE DEFAULT SYSDATE
5 );
Table created.
SQL> INSERT INTO demo_customers_seqver (id, name)
2 VALUES (demo_customers_seq.NEXTVAL, 'Tanaka Hanako');
1 row created.
SQL> select * from demo_customers_seqver;
ID NAME CREATED_A
---------- --------------- ---------
1 Tanaka Hanako 23-AUG-25
SQL> SELECT demo_customers_seq.CURRVAL FROM dual;
CURRVAL
----------
1
Common options
START WITH n— starting valueINCREMENT BY n— stepCACHE n / NOCACHE— in-memory cache for speed (gaps can occur on failures)CYCLE / NOCYCLE— wrap to min after max or not
Pros / Cautions
- Highly configurable; reusable across tables.
CURRVALis available after you callNEXTVALin the session.- Gaps are normal (cache/rollback/parallel insert, etc.).
IDENTITY vs. SEQUENCE (quick sketch)
┌──────────────┬─────────────────────────────────────────────┐
│ IDENTITY │ Column-level auto-number; part of the table │
├──────────────┼─────────────────────────────────────────────┤
│ SEQUENCE │ Independent object; use NEXTVAL/CURRVAL │
├──────────────┼─────────────────────────────────────────────┤
│ Easy setup │ ◎ (very simple) │
│ Flexibility │ △ (limited) │
│ │ ◎ (start/step/cache/cycle tunable) │
└──────────────┴─────────────────────────────────────────────┘
Get the Generated Value Immediately: The RETURNING Clause
RETURNING ... INTO gives your program column values right after an INSERT/UPDATE/DELETE. It’s commonly used for single-row operations.
Why it’s handy
- Immediately fetch the newly generated ID (primary key).
- Fetch defaulted values (like
SYSDATE) or generated columns in one round trip.
Note (SQL*Plus): The
VARIABLEcommand does not support DATE. When you need to receive a date/time, declare aVARCHAR2variable and useTO_CHARon theRETURNINGside.
How to use (SQL*Plus/SQLcl)
VARIABLE v_new_id NUMBER
VARIABLE v_when VARCHAR2(32)
INSERT INTO demo_customers (name, email)
VALUES ('Yamada Taro','yamada.taro@example.com')
RETURNING id, TO_CHAR(joined_on,'YYYY-MM-DD HH24:MI:SS')
INTO :v_new_id, :v_when;
PRINT v_new_id
PRINT v_when
Command execution example
SQL> VARIABLE v_new_id NUMBER
SQL> VARIABLE v_when VARCHAR2(32)
SQL> INSERT INTO demo_customers (name, email)
2 VALUES ('Yamada Taro','yamada.taro@example.com')
3 RETURNING id, TO_CHAR(joined_on,'YYYY-MM-DD HH24:MI:SS')
4 INTO :v_new_id, :v_when;
1 row created.
SQL> select * from demo_customers;
ID NAME EMAIL JOINED_ON S
---------- --------------- ------------------------- --------- -
1 Sato Ichiro s.ichiro@example.com 23-AUG-25 A
1000 Yamada Taro yamada.taro@example.com 23-AUG-25 A
SQL> PRINT v_new_id
V_NEW_ID
----------
1000
SQL> PRINT v_when
V_WHEN
---------------------------------
2025-08-23 00:59:52
If joined_on is a TIMESTAMP column
RETURNING id, TO_CHAR(joined_on,'YYYY-MM-DD HH24:MI:SS.FF3')
INTO :v_new_id, :v_when;
Common patterns
- Combine with IDENTITY to capture the generated
id. - With SEQUENCE, you know the
idviaNEXTVAL, butRETURNINGis still useful to fetch other columns (e.g., values assigned by defaults).
Also works with UPDATE/DELETE (reference)
-- Receive the primary key of the row updated
VARIABLE v_id NUMBER
UPDATE demo_customers SET status='I' WHERE email='s.ichiro@example.com'
RETURNING id INTO :v_id;
-- Receive the primary key of the row deleted
VARIABLE v_del NUMBER
DELETE FROM demo_customers WHERE id=1
RETURNING id INTO :v_del;
Command execution example
SQL> VARIABLE v_id NUMBER
SQL> UPDATE demo_customers SET status='I' WHERE email='s.ichiro@example.com'
2 RETURNING id INTO :v_id;
1 row updated.
SQL> select * from demo_customers;
ID NAME EMAIL JOINED_ON S
---------- --------------- ------------------------- --------- -
1 Sato Ichiro s.ichiro@example.com 23-AUG-25 I
1000 Yamada Taro yamada.taro@example.com 23-AUG-25 A
SQL> PRINT v_id
V_ID
----------
1
SQL> VARIABLE v_del NUMBER
SQL> DELETE FROM demo_customers WHERE id=1
2 RETURNING id INTO :v_del;
1 row deleted.
SQL> select * from demo_customers;
ID NAME EMAIL JOINED_ON S
---------- --------------- ------------------------- --------- -
1000 Yamada Taro yamada.taro@example.com 23-AUG-25 A
SQL> PRINT v_del
V_DEL
----------
1
Notes
- Primarily for single-row DML. For multi-row, consider PL/SQL’s
RETURNING BULK COLLECT INTO(advanced). - In applications (e.g., JDBC), you can also use getGeneratedKeys instead of SQL
RETURNING.
Common Errors and Fixes (quick reference)
-- Duplicate (e.g., same email)
ORA-00001: unique constraint (….) violated
→ Pre-check duplicates; enforce uniqueness with constraints and indexes.
-- NOT NULL violation (required column is NULL)
ORA-01400: cannot insert NULL into ("OWNER"."T"."COL")
→ Add DEFAULTs, validate on the app side, or revise column list.
-- Foreign key violation (child inserted without a parent)
ORA-02291: integrity constraint (….) violated - parent key not found
→ Insert the parent first; fix the loading order.
Transaction Basics (commit = confirm / rollback = cancel)
An INSERT is not permanent until COMMIT. Use ROLLBACK to undo.
SAVEPOINT sv1; -- checkpoint
INSERT INTO demo_customers (name) VALUES ('Temp User');
ROLLBACK TO sv1; -- go back to the checkpoint
COMMIT; -- finalize changes
Step-by-Step Execution (verified on 19c / Oracle Linux 7.9)
These are runnable minimal steps. Adjust tablespace and password policies to fit your environment.
1) Create a user (schema) — run as SYSDBA
-- In a CDB, switch to the target PDB first
-- sqlplus / as sysdba
CREATE USER appuser IDENTIFIED BY "Str0ng#Pass"
DEFAULT TABLESPACE users QUOTA UNLIMITED ON users;
GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE TO appuser;
2) Log in and create a table — run as APPUSER
-- sqlplus appuser/Str0ng#Pass
CREATE TABLE customers (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
email VARCHAR2(255) UNIQUE,
joined_on DATE DEFAULT SYSDATE,
status CHAR(1) DEFAULT 'A' CHECK (status IN ('A','I'))
);
3) Insert a single row (explicit column list)
INSERT INTO customers (name, email, status)
VALUES ('Suzuki Jiro','suzuki.jiro@example.com','A');
-- Omitted columns get DEFAULTs (joined_on = SYSDATE)
INSERT INTO customers (name, email)
VALUES ('Kato Miki','kato.miki@example.com');
4) Insert dates and times safely
INSERT INTO customers (name, email, joined_on)
VALUES (
'Shimizu Kana',
'shimizu.kana@example.com',
TO_DATE('2025-08-23','YYYY-MM-DD')
);
5) Retrieve the new ID on the spot
VARIABLE new_id NUMBER
INSERT INTO customers (name) VALUES ('Nagasawa Mei')
RETURNING id INTO :new_id;
PRINT :new_id;
COMMIT; -- confirm
6) Verification SQL
-- Row count
SELECT COUNT(*) FROM customers;
-- Most recent rows
SELECT * FROM customers ORDER BY id DESC FETCH FIRST 5 ROWS ONLY;
-- Unique index on email
SELECT index_name, uniqueness
FROM user_indexes
WHERE table_name = 'CUSTOMERS';
Practical Tips (what to watch for)
- Always specify column names:
INSERT INTO T VALUES(...)breaks easily when columns are added later. - DEFAULT vs. NULL: They are not the same; analytics/auditing may treat them differently.
- Explicit date/time formats: Use
TO_DATE/TO_TIMESTAMP. - Minimize mixed numbering strategies: Avoid mixing manual IDs with IDENTITY/SEQUENCE.
- Plan commit intervals: For bulk inserts, too frequent commits hurt consistency; too few inflate UNDO.
INSERT ... SELECT will be covered in a separate article
- Used to copy data between tables or ingest query results in bulk.
- With large volumes, plan for execution plans, indexes, and locking. We’ll cover runnable examples and best practices in a dedicated post.
Summary
- Explicit column lists make INSERT safer and more maintainable.
- IDENTITY is simple; SEQUENCE offers control. Choose based on your requirements.
RETURNINGlets you grab generated IDs immediately.- Explicit date/time formats avoid surprises from implicit conversions.
- Design commit intervals, constraints, and indexes as part of an end-to-end operation plan.
This article targets Oracle Database 19c (other versions may differ in screens and defaults).
[reference]
INSERT


コメント