UPSERT 仅在 PostgreSQL 中提供时使用 ID

UPSERT using ID only when provioded in PostgreSQL

对于以下 PostgreSQL 查询,我想“插入”一行,这样如果我提供的行数据包含字段“id”的数据,它将被使用,如果没有,它将由 postgres 自动生成。这可以执行吗?

架构

create table if not exists spotify_crons (
      id uuid default uuid_generate_v4 () primary key
    , name varchar(32) unique
    , seed_artists varchar(32)
    , seed_tracks varchar(32)
    , seed_genres varchar(256)
    , created_at timestamptz not null default now()
    , updated_at timestamptz not null default now()
);
comment on column spotify_crons.id is 'The UUID of the cron entry';
comment on column spotify_crons.name is 'The unique name of the cron entry';
comment on column spotify_crons.seed_artists is 'The spotify artist seed of the cron entry';
comment on column spotify_crons.seed_tracks is 'The spotify track seed of the cron entry';
comment on column spotify_crons.seed_genres is 'The spotify genre seed of the cron entry';
comment on column spotify_crons.created_at is 'The time of creation for the cron entry';
comment on column spotify_crons.updated_at is 'The time of last update for the cron entry';

查询

insert into spotify_crons
    (
          id
        , name
        , seed_artists
        , seed_tracks
        , seed_genres
        , created_at
        , updated_at
    )
values
    (
          case
            when %(id)s is distinct from null
            then %(id)s
            else gen_random_uuid()
          end
        , %(name)s
        , %(seed_artists)s
        , %(seed_tracks)s
        , %(seed_genres)s
        , now()
        , now()
    )
on
    conflict (id)
do
    update
set
    name = %(name)s
  , seed_artists = %(seed_artists)s
  , seed_tracks = %(seed_tracks)s
  , seed_genres = %(seed_genres)s
  , updated_at = now()
returning id
;

示例:

# Should insert new row with auto generated ID
{ "id": None, "name": "Hello", ...}

# Should insert the row with the provided UUID
{ "id": "some_uuid_that_doesn't exist", "name": "Hello", ...}

# Should update the row with the matching UUID with new data
{ "id": "some_uuid_that_exists", "name": "Hello", ...}

PS:如果重要的话,我正在使用 Python 3.7psycopg 3

像这样的东西应该可以工作:

INSERT INTO spotify_crons (id, name,
                          -- ...
                          )
VALUES (COALESCE(%(id)s::UUID, uuid_generate_v4()),
        %(name)s,
        -- ...
       )
ON CONFLICT (id)
DO UPDATE SET name=EXCLUDED.name,
              -- ...
  • 像这样在 COALESCE 表达式中使用 DEFAULT 关键字是行不通的,但如果您知道要生成一个v4 随机 UUID 无论如何:COALESCE(%(id)s::UUID, DEFAULT).

  • 如果您与唯一名称约束发生冲突,您可能还会 运行 遇到其他问题,在这种情况下 可能会引起您的兴趣。