我用下面的简单表格演示了这个问题.(实际的表和JSON文档有更多的字段.)

CREATE table contact (
    id bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    firstname VARCHAR,
    lastname VARCHAR,
    birthday timestamp with time zone NOT NULL
);

我正在try 使用jsonb_populate_record从JSONB插入到这个表中:

INSERT INTO contact (firstname, lastname, birthday)
SELECT (jsonb_populate_record(NULL::contact, 
'{
    "firstname": "John",
    "lastname": "Doe",
    "birthday": "2023-09-28"
}'
)).*;

此操作失败,并显示错误:

ERROR: INSERT has more expressions than target columns
LINE 1: ...O contact (firstname, lastname, birthday) SELECT jsonb_popu...

我知道错误来自不包含id键和值的JSONB.因此,jsonb_populate_record函数正在创建一条包含id列的记录,但由于INSERT中没有指定它,所以它失败了.

我try 将id添加到INSERT INTO contact (id, ....中,但失败了,错误为id为空(因为我的JSONB中没有任何id).

我怎么才能让它工作,使id是表中指定的GENERATED BY DEFAULT AS IDENTITY

EDIT:

我找到了一个解决方案:

INSERT INTO contact (id, firstname, lastname, birthday)
SELECT (jsonb_populate_record(NULL::contact, jsonb_set('{
"firstname": "John",
"lastname": "Doe",
"birthday": "2023-09-28"
}', '{id}', to_jsonb(nextval(pg_get_serial_sequence('contact', 'id')))))).*;

然而,这之后生成的id似乎跳过了4位数:

select * from contact;
 id | firstname | lastname |        birthday        
----+-----------+----------+------------------------
 10 | John      | Doe      | 2023-09-28 00:00:00-04
 14 | John      | Doe      | 2023-09-28 00:00:00-04
 18 | John      | Doe      | 2023-09-28 00:00:00-04
 22 | John      | Doe      | 2023-09-28 00:00:00-04

你知道为什么和如何避免这种情况吗?

推荐答案

还有另一种解决方案,一种不影响序列本身的解决方案.只需创建一个不带id的定制数据类型,并使用该类型:

CREATE TYPE CONTACT_BASE AS
(
    firstname VARCHAR,
    lastname  VARCHAR,
    birthday  TIMESTAMP
);

INSERT INTO contact (firstname, lastname, birthday)
SELECT (JSONB_POPULATE_RECORD(
        NULL::CONTACT_BASE -- this one
    , '{
          "firstname": "John",
          "lastname": "Doe",
          "birthday": "2023-09-28"
        }'
    )).*;

顺便问一下,为什么要用时间戳来表示出生日期呢?

Sql相关问答推荐

Oracle SQL中的累计总数

在SQL Server中使用LEFT连接包含特定记录

Trino/Presto sq:仅当空值位于组中第一个非空值之后时,才用值替换空值

了解放置时的连接

使用列表作为参数进行 Select ,如果为空,则在PostgreSQL中不使用参数进行 Select

冲突查询的UPDATE时违反非空约束

在Netezza SQL中将字符DataType转换为整型DataType

在SQL中,筛选其他列中只有一个值的ID

违反了完整性约束-值存在时找不到父键

如何向 mariadb 添加外键?

通过ID和数据找到每个不同的值

Postgresql:在链接表中判断相关表中插入值的条件

SQL ORACLE - 查找连续天数

在Snowflake中如何使用SQL对版本字符串进行排序?

忽略与给定列匹配的行的 LAG 函数

如何仅在满足条件时才按顺序在 SQL 中计数?

为数组中的每个元素从表中收集最大整数

基于源表的 SQL INSERT、UPDATE 和 DELETE

将单行中的多个行值转换为列

SQL中所有先前日期的累计总和