Inserting records
How to insert one row, insert thousands efficiently, and read back the id the database generated — plus the two rules that decide what actually gets written.
Insert a single row
insert() takes a table name and an array (or object) of column → value pairs.
It returns the generated primary key.
$id = $cdo->insert('users', [
'name' => 'Alice',
'email' => 'alice@example.com',
]);The returned id is the value of the first key of the entity you passed,
fetched via RETURNING on PostgreSQL/MariaDB or lastInsertId() on MySQL. See
Driver detection for why the two paths exist.
The primary key is the first key
insert() derives the returned column from array_key_first() of your entity —
before NULLs are stripped. Put your primary-key column first (even as
'id' => null) so the right value comes back. A null/absent auto-id column
still returns the generated id via the driver.
Two rules for what gets written
nullvalues are dropped. Any column whose value isnullis removed from theINSERT, so the column takes its database default or auto-generated value.- Objects are flattened. An object entity is converted with
get_object_vars(), so its public properties become columns.
$user = new stdClass();
$user->name = 'Bob';
$user->email = 'bob@example.com';
$user->note = null; // dropped — column keeps its default
$id = $cdo->insert('users', $user);Insert a batch
insertGroup() writes many rows with far fewer round-trips. It automatically
splits the input into chunks and emits one multi-row INSERT per chunk.
$users = [
['name' => 'Alice', 'email' => 'alice@example.com'],
['name' => 'Bob', 'email' => 'bob@example.com'],
// ... thousands more
];
$cdo->insertGroup('users', $users); // default chunk size 1000
$cdo->insertGroup('users', $users, chunkSize: 500);insertGroup() returns nothing — it is a bulk write, not an id fetch. An empty
input array is a no-op.
Keep row shapes consistent within a chunk
Each chunk builds its column list from the rows it contains. Give every row the
same keys so the generated multi-row INSERT lines up. Per-row null values are
still dropped individually. Details in
Batch & chunking.
Choosing a chunk size
chunkSize caps how many rows go into one statement, which keeps you under the
database’s bound-parameter and packet limits. Smaller chunks use less memory per
statement; larger chunks mean fewer round-trips. The default of 1000 is a safe
starting point — lower it if rows are very wide (many columns).
Handling duplicate keys
A plain insert into a row that violates a unique constraint throws a
CDOException. If you instead want insert-or-update (or insert-or-ignore),
use upsert / upsertGroup.
Related
- Upserts — insert-or-update on conflict
- Batch & chunking — how multi-row inserts are built
- CDO API —
insert/insertGroupsignatures - Parameter binding — how each value is typed