Как продолжить порядковый номер во время вставки на основе выбора - Postgres - PullRequest
0 голосов
/ 13 января 2020

Я использую PostgreSQL дБ. У меня есть две таблицы, как показано ниже

enter image description here

Я хотел бы добавить отсутствующие person_ids в Table_2, ссылаясь на записи из Table_1.

Если вы видите приведенные выше таблицы, вы можете заметить, что person_id = 2,4 из table_1 отсутствует в 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
);

enter image description here

Это то, что я пробный

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`

Я ожидаю, что мой вывод будет таким, как показано ниже. Обратите внимание, что мои реальные данные содержат более 50 тыс. Записей, и вновь добавленные записи должны продолжать последовательность как есть.

enter image description here

Ответы [ 2 ]

1 голос
/ 13 января 2020

В большинстве случаев, когда таблица имеет целочисленный первичный ключ, она назначается с помощью:

  • 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 (или даже оба вместе).
1 голос
/ 13 января 2020

Если sno в table_2 имеет последовательность или является последовательным столбцом, попробуйте это

Пример данных

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)

Редактировать (см. Комментарии)

Создать 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)
...