【问题标题】:How to continue sequence number during insert based on select - Postgres如何在基于选择的插入期间继续序列号 - Postgres
【发布时间】:2020-04-30 00:51:08
【问题描述】:

我正在使用 PostgreSQL 数据库。我有两个表,如下所示

我想通过引用 Table_1 中的记录来添加 Table_2 中缺少的 person_ids。

如果您看到上面的表格,您会注意到 table_1 中的 person_id = 2,4 在 table_2 中丢失了。

虽然我可以在论坛的帮助下做到这一点,但问题在于非空约束。

表2创建表定义如下图

CREATE TABLE Table_2(
   SNO INTEGER (20) UNIQUE NOT NULL,
   PERSON_ID INTERGER (20) NOT NULL,
   date_1 DATE NOT NULL,
   date_2 DATE NOT NULL,
   DEPT VARCHAR (10) NOT NULL
);

这是我尝试过的

INSERT into Table_2 (person_id,date_1,date_2,Dept) (select distinct person_id,TO_DATE('1900-01-01', 'YYYY-MM-DD'),TO_DATE('2900-12-30', 'YYYY-MM-DD'),'F' from Table_1 where person_id not in (select distinct person_id from Table_2))

这会导致如下所示的错误

`ERROR: null value in column "SNO" violates not-null constraint
DETAIL: Failing row contains (null, 2, 1900-01-01, 2900-12-30, F).
SQL state: 23502`

我希望我的输出如下所示。请注意,我的真实数据有超过 50K 条记录,新添加的记录应按原样继续。

【问题讨论】:

  • 我在上一个问题中告诉过你不要在表格中使用图像。然而你又这样做了......
  • 请在表1中显示CREATE TABLE。表1中SNOperson_id有什么区别?
  • 嗨@VesaKarjalainen - 对表格进行了一些更改。你可以看到更新的帖子。现在sno 列不在table_1
  • table_1sno 列吗? table_2 中的sno 有序列还是序列列?
  • 这不是CREATE TABLE 命令,也不是表1。这也不是表2,它有“性别”和/或“部门”吗?并且不要发布图像,发布代码有人可以复制粘贴。

标签: sql postgresql select insert where-clause


【解决方案1】:

如果table_2 中的sno 有一个序列或者是一个串行列,试试这个

样本数据

CREATE TABLE table_1 (person_id int, day_of_birth int, month_of_birth int, gender text);
INSERT INTO table_1 
VALUES (4,17,7,'M'),
       (2,15,3,'F');

CREATE TABLE table_2 (sno serial, person_id int, date_1 date, date_2 date, dept text);

INSERT INTO table_2 (person_id, date_1, date_2, dept)
VALUES (1,'1990-02-27','2020-03-13','A'),
       (3,'1990-02-28','2020-02-14','B');

插入查询

INSERT into Table_2 (person_id,date_1,date_2,dept) 
SELECT person_id, 
       TO_DATE('1900-01-01', 'YYYY-MM-DD'), 
       TO_DATE('2900-12-30', 'YYYY-MM-DD'),'F' 
FROM Table_1 WHERE person_id NOT IN (SELECT person_id FROM Table_2);

结果

SELECT * FROM table_2;
 sno | person_id |   date_1   |   date_2   | dept 
-----+-----------+------------+------------+------
   1 |         1 | 1990-02-27 | 2020-03-13 | A
   2 |         3 | 1990-02-28 | 2020-02-14 | B
   3 |         4 | 1900-01-01 | 2900-12-30 | F
   4 |         2 | 1900-01-01 | 2900-12-30 | F
(4 Zeilen)

编辑(参见 cmets)

创建一个sequence

CREATE SEQUENCE seq_sno START WITH 3;

之后,只需使用 nextval 将其放入插入中

INSERT INTO Table_2 (sno, person_id,date_1,date_2,dept) 
SELECT nextval('seq_sno'),person_id, 
       TO_DATE('1900-01-01', 'YYYY-MM-DD'), 
       TO_DATE('2900-12-30', 'YYYY-MM-DD'),'F' 
FROM Table_1 WHERE person_id NOT IN (SELECT person_id FROM Table_2);

SELECT * FROM table_2;
 sno | person_id |   date_1   |   date_2   | dept 
-----+-----------+------------+------------+------
   1 |         1 | 1990-02-27 | 2020-03-13 | A
   2 |         3 | 1990-02-28 | 2020-02-14 | B
   3 |         4 | 1900-01-01 | 2900-12-30 | F
   4 |         2 | 1900-01-01 | 2900-12-30 | F
(4 Zeilen)

【讨论】:

  • 那会失败。 SNONOT NULL 没有 DEFAULT,你必须给它一个值。
  • 与我在帖子中给出的代码有什么不同吗?
  • @TheGreat 检查我发布的创建表语句。它会自动顺序设置 sno 的值,而不在插入中传递它
  • 好的,很遗憾我不能使用create statement
  • 如果这是将新数据插入表 2 的唯一方法,那就没问题了。如果还有其他方法可以插入新行,我会使用触发器。
【解决方案2】:

在表具有整数主键的大多数情况下,它是使用以下方式分配的:

  • serial
  • generated always as identity
  • 序列号,可能使用触发器自动设置
  • 表示由业务定义的东西

您的桌子似乎缺少这一点。我会建议修理桌子,但如果你不能,你可以尝试:

insert into Table_2 (sno, person_id, date_1, date_2, Dept)
    select t2.max_sno + row_number() over (order by t1.person_id),
           t1.person_id, date '1900-01-01', date '2900-12-30', 'F' 
    from Table_1 t1 cross join
         (select max(t2.sno) as max_sno from table_2 t2) t2
    where not exists (select 1
                      from table_2 t2
                      where t2.person_id = t1.person_id
                     );

我真的不推荐这种方法,除非作为一种变通方法。正确的做法是把桌子修好。

注意事项:

  • 使用简单的日期常量。这使用 date 关键字,但您也可以使用 '2020-01-01'::date
  • NOT EXISTS 优于 NOT IN,因为它处理 NULL 值。
  • 整个WHERE 子句并不是防止重复的最佳方法。更好的方法是使用on conflict(甚至两者一起使用)。

【讨论】:

  • 您好,感谢您的回复。赞成。但这会引发错误ERROR: missing FROM-clause entry for table "t2"from clause is present
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 1970-01-01
  • 2010-10-03
  • 2013-04-05
相关资源
最近更新 更多