PostgreSQL вложенные INSERT/WITH для вставки внешних ключей

Я использую PostgreSQL 9.3, и я пытаюсь написать SQL script, чтобы вставить некоторые данные для модульных тестов, и я столкнулся с некоторой проблемой.

Скажем, у нас есть три таблицы, структурированные следующим образом:

------- Table A -------    -------- Table B --------    -------- Table C --------
id  | serial NOT NULL      id   | serial NOT NULL       id   | serial NOT NULL
foo | character varying    a_id | integer NOT NULL      b_id | integer NOT NULL
                           bar  | character varying     baz  | character varying

Столбцы B.a_id и C.b_id являются внешними ключами столбца id таблиц A и B соответственно.

То, что я пытаюсь сделать, - это вставить строку в каждую из этих трех таблиц с чистым SQL, не имея идентификатора, жестко закодированного в SQL (предположение о базе данных до запуска этого script кажется нежелательным, так как если эти предположения меняются, мне придется вернуться и повторно вычислить правильный идентификатор для всех тестовых данных).

Заметьте, что я понимаю, что могу сделать это программно, но в целом писать чистый SQL гораздо менее подробный, чем писать программный код для выполнения SQL, поэтому он имеет больше смысла для данных тестового набора.

В любом случае, вот запрос, который я написал, который, как я понял, будет работать:

WITH X AS (
    WITH Y AS (
        INSERT INTO A (foo)
        VALUES ('abc')
        RETURNING id
    )
    INSERT INTO B (a_id, bar)
    SELECT id, 'def'
    FROM Y
    RETURNING id
)
INSERT INTO C (b_id, baz)
SELECT id, 'ghi'
FROM X;

Однако это не сработает и приводит к тому, что PostgreSQL говорит мне:

ERROR:  WITH clause containing a data-modifying statement must be at the top level

Есть ли правильный способ написать этот тип запроса в целом, без жесткого кодирования значений ID?

(Здесь вы можете найти скрипт который содержит этот пример.)

Ответ 1

Не вставляйте общие табличные выражения, просто пишите один за другим:

WITH Y AS (
  INSERT INTO A (foo)
  VALUES ('abc')
  RETURNING id
), x as (
  INSERT INTO B (a_id, bar)
  SELECT id, 'def'
  FROM Y
  RETURNING id
)
INSERT INTO C (b_id, baz)
SELECT id, 'ghi'
FROM X;