INSERT, UPDATE, DELETE builders
Advanced5 min read·fw-07-005
sql
Concept
INSERT, UPDATE, DELETE builders complete the Query Builder's CRUD capabilities. While SELECT is the most complex, the write operations also benefit from a fluent interface and safe parameter binding.
INSERT:
- Single row:
INSERT INTO users (name, email) VALUES (?, ?). - Multiple rows:
INSERT INTO users (name, email) VALUES (?, ?), (?, ?)— compile all rows into one statement. INSERT OR IGNORE/INSERT IGNORE: Skip duplicates without error.INSERT ... ON DUPLICATE KEY UPDATE(MySQL) /ON CONFLICT DO UPDATE(PostgreSQL): Upsert.
UPDATE:
UPDATE users SET name = ?, email = ? WHERE id = ?.- ALWAYS include a WHERE clause.
update()withoutwhere()updates ALL rows. - Return affected row count.
UPDATE users SET count = count + 1 WHERE id = ?— increment without reading first.
DELETE:
DELETE FROM users WHERE id = ?.- Return affected row count.
- ALWAYS include WHERE clause.
delete()withoutwhere()deletes ALL rows. - Soft delete is an UPDATE:
UPDATE users SET deleted_at = NOW() WHERE id = ?.
Safety check: Some builders refuse to execute UPDATE or DELETE without a WHERE clause. This prevents accidental full-table modifications.
lastInsertId(): After INSERT, get the auto-incremented primary key: $pdo->lastInsertId().
Code Example
php
<?php
namespace Framework\Database;
class QueryBuilder
{
private array $sets = []; // for UPDATE: ['column' => value]
private array $bindings = ['where' => [], 'insert' => [], 'update' => []];
// INSERT
public function insert(array $values): bool
{
$columns = implode(', ', array_keys($values));
$placeholders = implode(', ', array_fill(0, count($values), '?'));
$sql = "INSERT INTO {$this->table} ({$columns}) VALUES ({$placeholders})";
return $this->connection->insert($sql, array_values($values));
}
public function insertGetId(array $values): string|false
{
$this->insert($values);
return $this->connection->lastInsertId();
}
public function insertMany(array $rows): bool
{
if (empty($rows)) return true;
$columns = implode(', ', array_keys($rows[0]));
$rowPlaceholders = array_fill(0, count($rows),
'(' . implode(', ', array_fill(0, count($rows[0]), '?')) . ')'
);
$sql = "INSERT INTO {$this->table} ({$columns}) VALUES " . implode(', ', $rowPlaceholders);
$flat = array_merge(...array_map('array_values', $rows));
return $this->connection->insert($sql, $flat);
}
// UPDATE
public function update(array $values): int
{
$sets = implode(', ', array_map(fn($col) => "{$col} = ?", array_keys($values)));
$sql = "UPDATE {$this->table} SET {$sets}";
if (!empty($this->wheres)) {
[$whereClause, $whereBindings] = $this->compileWheres();
$sql .= " WHERE {$whereClause}";
return $this->connection->update($sql, array_merge(array_values($values), $whereBindings));
}
return $this->connection->update($sql, array_values($values));
}
public function increment(string $column, int $amount = 1): int
{
return $this->update([$column => $this->raw("{$column} + {$amount}")]);
}
// DELETE
public function delete(): int
{
$sql = "DELETE FROM {$this->table}";
if (!empty($this->wheres)) {
[$whereClause, $whereBindings] = $this->compileWheres();
$sql .= " WHERE {$whereClause}";
return $this->connection->delete($sql, $whereBindings);
}
return $this->connection->delete($sql, []);
}
private function raw(string $expr): RawExpression
{
return new RawExpression($expr);
}
}
// Usage
$builder->table('users')->insert(['name' => 'Alice', 'email' => 'alice@example.com']);
$id = $builder->table('users')->insertGetId(['name' => 'Bob', 'email' => 'bob@example.com']);
$affected = $builder->table('users')->where('id', 42)->update(['name' => 'Alice Smith']);
$builder->table('posts')->where('user_id', 42)->increment('view_count');
$deleted = $builder->table('sessions')->where('expires_at', '<', date('Y-m-d H:i:s'))->delete();