sql - 将 JSON 插入到两个表中并返回序列号

标签 sql database postgresql insert plpgsql

我正在尝试INSERT 一条新记录到 Postgres 9.6 数据库中,并获取该新插入记录的 ID 并将其传递到另一个表以供外键引用。数据是 JSON 格式,我想将 JSON blob 存储在行字段中,而不是将其解析出来。但是,我收到有关 NULL 值违反 PRIMARY KEYNOT-NULL 约束的错误。

我假设我的代码应该在 my_data 表中创建一个新记录(使用自动生成的 data_iddata_fields填充了我的 JSON 对象),但我的假设似乎不正确。

我缺少或没有完全掌握什么?下面是复制我的设置的代码。

表格:

CREATE TABLE my_data(
  data_id SERIAL PRIMARY KEY,
  data_fields JSONB
);

CREATE TABLE request_data(
    request_id SERIAL PRIMARY KEY,
    request_timestamp TIMESTAMP WITH TIME ZONE,
    data_id INTEGER REFERENCES my_data(data_id),
    record_count INTEGER,
    completedStatus boolean
);

功能:

CREATE OR REPLACE FUNCTION updateData (
dataFields JSONB,
requestTimestamp TIMESTAMP WITH TIME ZONE,
recordCount INTEGER,
completedStatus boolean,
OUT new_record_id INTEGER
)
RETURNS integer AS $$
BEGIN
INSERT INTO my_data SELECT * FROM jsonb_populate_recordset(NULL::my_data, $1::jsonb) RETURNING data_id INTO new_record_id;
INSERT INTO request_data (request_timestamp, data_id, record_count, completed_status) VALUES($2, new_record_id, $3, $4);
END;
$$ LANGUAGE plpgsql;

调用:

SELECT updateData (
'[{"identity": "personA", "timestamp": "2017-09-15T20: 03: 12+00: 00"},
{"identity": "personB", "timestamp": "2017-09-15T20: 03: 12+00: 00"},
{"identity": "personC", "timestamp": "2017-09-15T20: 03: 12+00: 00"}]'
 '2017-09-29', 
 3, 
 true)

错误:

ERROR: null value in column "data_id" violates not-null constraint
SQL state: 23502
Detail: Failing row contains (null, null).

my_data 表的预期结果:

data_id     | data_fields
------------+------------------------------
    1       | [{"identity": "personA", "timestamp": "2017-09-15T20: 03: 12+00: 00"},{"identity": "personB", "timestamp": "2017-09-15T20: 03: 12+00: 00"},{"identity": "personC", "timestamp": "2017-09-15T20: 03: 12+00: 00"}]

request_data 表的预期结果:

request_id  |    request_timestamp     | data_id | record_count | completed_status
------------+--------------------------+---------+--------------+-------------------
    1       |   2017-09-29             |  1      |  3           |   true

最佳答案

@Fahad 指出了主要的逻辑错误。

但您不需要在 ($1::jsonb) 中进行强制转换,因为输入参数已键入 jsonb

我会推荐一个带有数据修改 CTE 的单个查询,将两个插入组合在一个简单的 SQL 函数中——而不是两个 INSERT 查询,中间有一个赋值一个 PL/pgSQL 函数。更短、更不容易出错、更快:

CREATE OR REPLACE FUNCTION update_data(data_fields jsonb
                                     , request_timestamp timestamptz
                                     , recordcount integer
                                     , completed_status boolean)
  RETURNS integer AS
$func$
   WITH ins1 AS (
      INSERT INTO my_data(data_fields)
      VALUES ($1)  -- no need to cast
      RETURNING data_id
      )
   INSERT INTO request_data(request_timestamp, data_id, record_count, completed_status)
   SELECT $2, i.data_id, $3, $4
   FROM   ins1 i
   RETURNING data_id
$func$  LANGUAGE sql;

我也统一到小写拼写。您混合使用了命名约定,导致 completedStatuscompleted_status 不匹配。我的一贯建议是避免在 Postgres 中对标识符进行大小写混合拼写。

相关:

关于sql - 将 JSON 插入到两个表中并返回序列号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46590650/

相关文章:

django - 如何管理非默认 Django 数据库

sql - 给定一列有效日期,是否有 SQL 语句可以将其转换为日期范围?

SQL 错误 #1064

sql - 优化使用 where 子句和大量 AND/OR 的递归 postgres 查询

database - 将 PostgreSQL 数据库复制到另一台服务器

python - Django 重定向到上一页保存查询

java - 与 Postgres 数据库的连接丢失

php - mysql : select rows from table 1 and test if rows exists in table 2

MySQL 自然左外连接与左外连接

python - 炼金术;将主键设置为预先存在的数据库表(不使用 sqlite)