Package · cdo

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.

php
$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

  1. null values are dropped. Any column whose value is null is removed from the INSERT, so the column takes its database default or auto-generated value.
  2. Objects are flattened. An object entity is converted with get_object_vars(), so its public properties become columns.
php
$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.

php
$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.