简体   繁体   English

如何插入通过外键引用另一个 postgres 表的行,并在它不存在时创建外行?

[英]How can I insert a row that references another postgres table via foreign key, and creates the foreign row too if it doesn't exist?

In Postgres, is there a way to atomically insert a row into a table, where one column references another table, and we look up to see if the desired row exists in the referenced table and inserts it as well if it is not?在 Postgres 中,有没有办法将一行原子插入到表中,其中一列引用另一个表,然后我们查找所需的行是否存在于引用的表中,如果不存在,则将其插入?

For example, say we have a US states table and a cities table which references the states table:例如,假设我们有一个美国州表和一个引用州表的城市表:

CREATE TABLE states (
  state_id serial primary key,
  name text
);
CREATE TABLE cities (
  city_id serial,
  name text,
  state_id int references states(state_id)
);

When I want to add the city of Austin, Texas, I want to be able to see whether Texas exists in the states table, and if so use its state_id in the new row I'm inserting in the cities table.当我想添加德克萨斯州奥斯汀市时,我希望能够查看德克萨斯州是否存在于州表中,如果存在,则在我插入城市表的新行中使用它的 state_id。 If Texas doesn't exist in the states table, I want to create it and then use its id in the cities table.如果州表中不存在德克萨斯州,我想创建它,然后在城市表中使用它的 id。

I tried this query, but I got an error saying我试过这个查询,但我得到一个错误说

ERROR:  WITH clause containing a data-modifying statement must be at the top level
LINE 2:   WITH inserted AS (
               ^
WITH state_id AS (
  WITH inserted AS (
         INSERT INTO states(name)
           VALUES ('Texas')
           ON CONFLICT DO NOTHING
           RETURNING state_id),
       already_there AS (
         SELECT state_id FROM states
           WHERE name='Texas')
  SELECT * FROM inserted
  UNION
  SELECT * FROM already_there)
INSERT INTO cities(name, state_id)
  VALUES
    ('Austin', (SELECT state_id FROM state_id));

Am I overlooking a simple solution?我是否忽略了一个简单的解决方案?

You can force the insert statement to return a value:您可以强制insert语句返回一个值:

WITH inserted AS (
      INSERT INTO states (name)
          VALUES ('Texas')
          ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.NAME
          RETURNING state_id
     )
. . .

The DO UPDATE SET forces the INSERT to return something. DO UPDATE SET强制INSERT返回一些东西。

I notice that you don't have a unique constraint, so you also need that:我注意到您没有唯一约束,因此您还需要:

ALTER TABLE states ADD CONSTRAINT unq_state_name
    UNIQUE (name);

Otherwise the ON CONFLICT doesn't have anything to work with.否则ON CONFLICT没有任何可用的东西。

Here is one option:这是一种选择:

with inserted as (
    insert into states(name) values ('Texas')
    on conflict do nothing
    returning state_id
)
insert into cities(name, state_id)
values (
    'Dallas', 
    coalesce(
        (select state_id from inserted),
        (select state_id from states where name = 'Texas')
    )
);

The idea is to attempt to insert in a CTE, and then, in the main insert, check if a value was inserted, else select it.这个想法是尝试在 CTE 中插入,然后在主插入中检查是否插入了值,否则选择它。

For this to work properly, you need a unique constraint on states(name) :为了使其正常工作,您需要对states(name)的唯一约束:

create table states (
  state_id serial primary key,
  name text unique
);

Demo on DB Fiddlde DB Fddlde 上的演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 SQL-SERVER 程序如何在一个表中插入行,然后将行插入到另一个表中作为外键链接到另一个表 - SQL-SERVER Procedure How do i insert row one table then insert row into another table link to another table as foreign key 如何在我的数据库中插入具有外键的行而不在链接表中添加行? - How can I insert a row in my database that has a foreign key without adding a row in the linked table? 如何在表中插入带有外键的行? - How to insert row in table with foreign key to itself? 用外键将行插入表中 - Insert row into a table with foreign key 如何使用引用复合键的外键插入行 - How to insert a row with a foreign key that references a composite key 仅当 MariaDB 中不存在具有非唯一外键的行时才插入 - Insert only if row with non uniqe foreign key doesn't already exist in MariaDB 如果 Postgresql 的父表中不存在外键,则忽略复制(读取)该行 - Ignore copy(reading) the row if the foreign key doesn't exist in the parent table in Postgresql FOREIGN KEY SAME TABLE错误-但外键不存在 - FOREIGN KEY SAME TABLE error - but foreign key doesn't exist 在PHP中使用外键将行插入表中 - Insert row into a table with foreign key inside PHP 是否可以在FOREIGN KEY的子表中插入行? - Is it possible to insert row into the child table of FOREIGN KEY?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM