我使用的是PostgreSQL9.3,并且我试图编写一个SQL脚本来为单元测试插入一些数据,但是我遇到了一些问题.

假设我们有三张桌子, struct 如下:

------- 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_idC.b_id分别是表ABid列的外键.

我要做的是用纯SQL将一行插入到这三个表中,而不将ID硬编码到SQL中(在运行此脚本之前对数据库进行假设似乎是不可取的,因为如果这些假设发生变化,我将不得不返回并重新计算所有测试数据的正确ID).

请注意,我确实意识到我可以通过编程实现这一点,但一般来说,编写纯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值进行硬编码?

(您可以找到包含此示例的小提琴here.)

推荐答案

不要嵌套公用表表达式,一个接一个地写就行了:

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;

Database相关问答推荐

Postgresql 服务器:允许访问私有网络内的远程连接,而不是外部网络

MongoDB 中的 OVER PARTITION 类似功能

需要未提供的参数@ID?

MySQL 慢查询日志(log) - 慢有多慢?

tzname字段/时区标识符名称的最大长度

基于邮政编码的纬度和经度

Spring Framework 中的默认隔离级别

存储所有排列的模式数据库

使 H2 将引用的名称和未引用的名称视为相同

连接池策略效果怎样?

是否有任何数据库支持自动索引创建?

如何更改 MySQL DB 中所有表的前缀?

MongoDB中的数据库数据大小

SQL Server 自动备份

多个和单个索引

MySQL:为什么使用 VARCHAR(20) 而不是 VARCHAR(255)?

在具有所需 ForeignKey 引用的 Django (1.8) 应用程序之间移动模型

DBMS中数据模型和数据库模式的区别?

做或不做:将图像存储在数据库中

在 Heroku 上预编译assets时如何普遍跳过数据库接触