Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql插入(如果不存在)_Sql_Postgresql - Fatal编程技术网

Postgresql插入(如果不存在)

Postgresql插入(如果不存在),sql,postgresql,Sql,Postgresql,我有以下疑问 INSERT INTO address (house_number, street, city_id) values(11, 'test st', (select id from city where LOWER(city) = LOWER('somecity'))) 是否仍要在city表中插入somecity如果城市中不存在somecity,则在插入后,它将返回插入行的ID 我确实发现这个答案说upsert可以用来实现这一点 但是我找不到如果select不返回行则插入的

我有以下疑问

INSERT INTO address (house_number, street, city_id)
    values(11, 'test st', (select id from city where LOWER(city) = LOWER('somecity')))
是否仍要在city表中插入somecity如果城市中不存在somecity,则在插入后,它将返回插入行的ID

我确实发现这个答案说upsert可以用来实现这一点


但是我找不到如果select不返回行则插入的示例。

您可以:

使用此设置:

DROP TABLE IF EXISTS test_address;
DROP TABLE IF EXISTS test_city;
CREATE TABLE test_address (
    house_number int
    , street text
    , city_id int
    );
CREATE TABLE test_city (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
    , city text 
    );
CREATE UNIQUE INDEX test_city_uniq_idx ON test_city USING btree (lower(city));
INSERT INTO test_city (city) VALUES ('Somecity');
通过上面的插入,查询

SELECT * FROM test_address;
屈服

| house_number | street  | city_id |
|--------------+---------+---------|
|           11 | test st |       1 |
| id | city     |
|----+----------|
|  1 | somecity |

屈服

| house_number | street  | city_id |
|--------------+---------+---------|
|           11 | test st |       1 |
| id | city     |
|----+----------|
|  1 | somecity |
请注意,CTE将替换

(select id from city where LOWER(city) = LOWER('somecity'))
插入。。关于冲突。。执行更新语句:

INSERT INTO test_city (city) VALUES ('somecity')
ON CONFLICT (lower(city)) DO UPDATE SET city = excluded.city
RETURNING id, city
INSERT ... ON CONFLICT (lower(city))
我用做更新,而不是什么都不做,以便返回id,城市将始终返回一些东西。如果使用DoNothing,则在发生冲突时不会返回任何内容

但是请注意,使用city=excluded.city的结果是原始的“Somecity” 被“某地”取代。我不确定您是否会认为这种行为是可以接受的,但不幸的是,我还没有弄清楚在发生冲突时如何什么也不做,同时返回id和city

上述解决方案可能存在的另一个问题是,我在lowercity上使用了唯一索引:

这允许您在INSERT语句中使用相同的条件:

INSERT INTO test_city (city) VALUES ('somecity')
ON CONFLICT (lower(city)) DO UPDATE SET city = excluded.city
RETURNING id, city
INSERT ... ON CONFLICT (lower(city))
作为SELECT语句中出现的条件LOWERcity=LOWER'somecity'的替代。它产生了期望的效果,但折衷是现在您有了一个唯一的索引 在低层

关于 如何插入到两个以上的表中:

可以,后续CTE甚至可以引用先前的CTE。比如说,

CREATE UNIQUE INDEX city_uniq_idx ON city USING btree (lower(city));
CREATE UNIQUE INDEX state_uniq_idx ON state USING btree (lower(state_code));

WITH tmpcity AS 
(
   INSERT INTO
      city (city) 
   VALUES
      (
         'Miami'
      )
      ON CONFLICT (lower(city)) DO 
      UPDATE
      SET
         city = excluded.city RETURNING id, city
)
, tmpstate as 
(
   INSERT INTO
      state (state_code) 
   VALUES
      (
         'FL'
      )
      ON CONFLICT (lower(state_code)) DO 
      UPDATE
      SET
         state_code = excluded.state_code RETURNING id, state_code
)
INSERT INTO
   address (house_number, street, city_id, state_id) 
   SELECT
      house_number,
      street,
      tmpcity.id,
      tmpstate.id 
   FROM
      (
      VALUES
         (
            12,
            'fake st.',
            'Miami',
            'FL'
         )
      )
      val (house_number, street, city, state_code) 
      LEFT JOIN
         tmpcity USING (city) 
      LEFT JOIN
         tmpstate USING (state_code)
         ON CONFLICT (street) DO NOTHING

这里最好的选择是在地址表上使用触发器,在城市中进行查找,如果不存在则插入。另一个选择是创建一个函数进行查找,当城市不存在时,插入它并返回IDaaaaa,并使此注释更有趣:夜王做得好!B您可以在地址表上创建一个视图,该视图使用城市名称和触发器来完成您想要的任务。@JorgeCampos是否有使用触发器将数据插入另一个表的示例?谢谢您的回答,我使用的是您的第一个CTE示例,它运行良好,我如何向其中添加更多类似城市的表?我还有一个状态表和zipcode表。你可以,后续的CTE甚至可以引用之前的CTE。这就是我构建的,有些东西告诉我我搞砸了。我想你差不多做到了,除了值元组应该重复'Miami','FL',连接条件应该是使用state_代码左连接tmpstate。我已经编辑了上面的帖子来说明我的意思。谢谢,这是可行的,但我在为county表添加CTE时遇到了另一个复杂问题。由于在某些情况下,一个县的相同名称可能属于多个州,因此我必须为county表的两列创建索引。使用btree lowercounty、state\u id在county上创建唯一索引county\u uniq\u idx;但ON CONFLICT仅支持一列。我尝试使用此处显示的冲突约束,但不幸的是,这不起作用。你认为什么是最好的解决方案?