DML — Data Manipulation Language
Goal
Справочник поддерживаемых DML-операций и поведение mutation policy.
INSERT
INSERT INTO t (id, v) VALUES (1, 100);
INSERT INTO t (id, v) VALUES (2, 200), (3, 300);
Для секционированных таблиц INSERT в родительскую таблицу автоматически маршрутизирует строку в подходящую
партицию. Если подходящая партиция (и DEFAULT) отсутствует — 23514 check_violation.
INSERT … SELECT
RM-0.6.3.7 (RFC-2026-497, S8): источник INSERT — произвольный
SELECT-запрос. Колонки результата сопоставляются с целевыми по позиции
(или по явному списку колонок); SERIAL/IDENTITY/DEFAULT резолвятся
для каждой строки независимо.
INSERT INTO archive (id, v) SELECT id, v FROM t WHERE created_at < '2025-01-01';
INSERT INTO log (note) SELECT 'rebuilt:' || name FROM rebuilt_items;
INSERT … ON CONFLICT (UPSERT)
RM-0.6.3.7 (RFC-2026-497, S9): поддерживается одно-колоночный конфликтный
target (или PK по умолчанию). EXCLUDED.<col> ссылается на предложенную
строку.
-- DO NOTHING (раннее поведение, теперь принимает явный target):
INSERT INTO t (id, v) VALUES (1, 100) ON CONFLICT (id) DO NOTHING;
-- DO UPDATE SET ... [WHERE ...]
INSERT INTO counters (key, n)
VALUES ('hits', 1)
ON CONFLICT (key) DO UPDATE SET n = counters.n + EXCLUDED.n;
-- WHERE-фильтр над существующей строкой (PG-семантика: конфликт + WHERE-false = silent no-op):
INSERT INTO inventory (sku, qty)
VALUES ('A', 5)
ON CONFLICT (sku) DO UPDATE SET qty = EXCLUDED.qty
WHERE inventory.qty < EXCLUDED.qty;
Не поддерживается:
- мультиколоночный target (
ON CONFLICT (a, b)) →0A000; ON CONFLICT ON CONSTRAINT <name>→0A000.
UPDATE
UPDATE t SET v = 999 WHERE id = 1;
Начиная с RM-0.6.5.5, UPDATE SET поддерживает функциональные выражения и приведение типов:
UPDATE t SET write_date = NOW() WHERE id = 1;UPDATE t SET ts = '2026-05-07 14:30:00'::timestamp WHERE id = 1;UPDATE t SET day = date_trunc('day', NOW()) WHERE id = 1;
Поддерживаются NOW(), CURRENT_TIMESTAMP, CURRENT_DATE, date_trunc() и явные CAST (синтаксис ::).
DELETE
DELETE FROM t WHERE id = 2;
RETURNING
RM-0.6.3.7 (RFC-2026-497, S10): RETURNING поддержан для multi-row
INSERT, UPDATE, DELETE. В проекции допустимы *, явный список
колонок и выражения. Для INSERT ... ON CONFLICT DO UPDATE возвращается
пост-апдейт строка (как в PostgreSQL).
INSERT INTO t (v) VALUES (100), (200), (300) RETURNING id, v;
UPDATE t SET v = v + 1 WHERE v > 0 RETURNING id, v AS new_v;
DELETE FROM t WHERE v IS NULL RETURNING id;
Sequence functions
RM-0.6.3.7 (RFC-2026-497): nextval / currval / setval для
объектов SEQUENCE (см. ddl.md — раздел «CREATE / ALTER /
DROP SEQUENCE»). Не транзакционные: gap-on-rollback корректное поведение.
SELECT nextval('s1'); -- 1, 2, 3, ...; overflow без CYCLE → 2200H
SELECT currval('s1'); -- последнее значение, выданное в ЭТОЙ сессии
SELECT setval('s1', 100); -- last_value=100, is_called=true; следующий nextval = 101
SELECT setval('s1', 50, false); -- следующий nextval = 50
currval — session-bound: возвращает значение последнего nextval
(или setval(_, _, true)) в той же pgwire-сессии. Если в текущей
сессии nextval ещё не вызывался — 55000 object_not_in_prerequisite_state,
независимо от того, что nextval был вызван в других сессиях.
SERIAL / IDENTITY
SERIAL / BIGSERIAL и GENERATED [ALWAYS|BY DEFAULT] AS IDENTITY
автоматически создают owned-последовательность <table>_<col>_seq,
которая удаляется вместе с таблицей.
CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);
INSERT INTO users (name) VALUES ('alice'), ('bob') RETURNING id;
-- id заполняется через nextval('users_id_seq')
CREATE TABLE orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
amount NUMERIC
);
INSERT INTO orders (id, amount) VALUES (42, 100);
-- → 428C9 generated_always: id колонка GENERATED ALWAYS
CREATE TABLE invoices (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
total NUMERIC
);
INSERT INTO invoices (id, total) VALUES (DEFAULT, 250) RETURNING id;
INSERT INTO invoices (id, total) VALUES (1000, 250); -- explicit OK
SELECT
SELECT id, v FROM t WHERE v > 50 ORDER BY id;
Подробно о запросах (CTE, JOIN, GROUP BY и т.д.) — см. queries.md.
TRUNCATE
TRUNCATE TABLE t;
TRUNCATE — DDL-сброс таблицы. Для append-only таблиц это единственный способ удалить данные.
Mutation policy enforcement
Mutation policy контролирует допустимые DML-операции на таблице.
append_only
| Операция | Результат |
|---|---|
INSERT | Разрешён |
UPDATE | Отклонён — 42809 wrong_object_type |
DELETE | Отклонён — 42809 wrong_object_type |
TRUNCATE | Разрешён (DDL reset) |
no_delete
| Операция | Результат |
|---|---|
INSERT | Разрешён |
UPDATE (non-PK, non-FK columns) | Разрешён |
UPDATE PK column (id) | Отклонён — 42809 wrong_object_type |
UPDATE FK child column | Отклонён — 42809 wrong_object_type |
DELETE | Отклонён — 42809 wrong_object_type |
TRUNCATE | Отклонён — 42809 wrong_object_type |
unrestricted
Все DML-операции разрешены (поведение по умолчанию).
Autocommit vs explicit transactions
По умолчанию каждый DML-запрос выполняется в autocommit-режиме (неявная транзакция, фиксируется сразу).
Для явных транзакций:
BEGIN;
INSERT INTO t (id, v) VALUES (10, 1000);
UPDATE t SET v = 2000 WHERE id = 10;
COMMIT;
ROLLBACK откатывает все изменения текущей транзакции.
Expected SQLSTATE
| Ситуация | SQLSTATE |
|---|---|
UPDATE/DELETE on append-only table | 42809 |
DELETE/TRUNCATE under no_delete | 42809 |
PK/FK UPDATE under no_delete | 42809 |
| Insert into partitioned table, no matching partition | 23514 |
nextval overflow (без CYCLE) | 2200H |
currval до первого nextval в этой сессии | 55000 |
setval value вне [MINVALUE..MAXVALUE] | 22023 |
Несуществующая sequence (nextval/currval/setval/DROP SEQUENCE без IF EXISTS) | 42P01 |
INSERT в GENERATED ALWAYS AS IDENTITY колонку с явным non-NULL | 428C9 |
INSERT ... ON CONFLICT (a, b) (multi-column target) | 0A000 |
INSERT ... ON CONFLICT ON CONSTRAINT <name> | 0A000 |
Links
- DDL (CREATE TABLE, mutation policy options): ddl.md
- Queries (SELECT details): queries.md
- Partitioning: partitioning.md
- Known issues: Known issues