2016-08-24 2 views
1

Я пытаюсь создать простую базу данных для телефонной книги. Это то, что я писал:Вставьте данные в строго нормированную БД и поддерживайте целостность (Postgres)

CREATE TABLE phone 
(
    phone_id SERIAL PRIMARY KEY, 
    phone CHAR(15), 
    sub_id INT, -- subscriber id -- 
    cat_id INT -- category id -- 
); 

CREATE TABLE category 
(
    cat_id SERIAL PRIMARY KEY, -- category id -- 
    cat_name CHAR(15)  -- category name -- 
); 

CREATE TABLE subscriber 
(
    sub_id SERIAL PRIMARY KEY, 
    name CHAR(20), 
    fname CHAR(20), -- first name -- 
    lname CHAR(20), -- last name -- 
); 

CREATE TABLE address 
(
    addr_id  SERIAL PRIMARY KEY, 
    country  CHAR(20), 
    city   CHAR(20), 
    street  CHAR(20), 
    house_num  INT, 
    apartment_num INT 
); 

-- many-to-many relation -- 
CREATE TABLE sub_link 
(
    sub_id INT REFERENCES subscriber(sub_id), 
    addr_id INT 
); 

Я создал таблицу ссылок на многие ко многим отношения, потому что немногие люди могут жить по тому же адресу и один человек может жить в разных местах в разное время.

Но я не могу понять, как добавить данные в сильно нормированную БД, как это, и поддерживать целостность данных.

Первое улучшение был то, что я добавил inique ключа на таблице адресов bacause этой таблицы не должен содержать дублированные данные:

CREATE TABLE address 
(
    addr_id  SERIAL PRIMARY KEY, 
    country  CHAR(20), 
    city   CHAR(20), 
    street  CHAR(20), 
    house_num  INT, 
    apartment_num INT, 
    UNIQUE (country, city, street, house_num, apartment_num) 
); 

Теперь проблема заключается в том, чтобы добавить новую запись о каком-то человеке в БД. Я думаю, что я должен использовать следующий порядок действий:

  1. вставить запись в таблицу subscriber, потому что sub_link и phone таблицы должны использовать идентификатор нового абонента.

  2. Впишите запись в таблицу address, так какдолжен существовать до добавления записи в sub_link.

  3. Ссылка последние записи из subscriber и address в sub_link таблица. Но на этом этапе у меня возникла новая проблема: как я могу получить sub_id и addr_id с шагов 1) и 2) в PostgreSQL?

  4. Затем мне нужно вставить запись в таблицу phone. Как и на этапе 3), я не знаю, как эффективно получить sub_id из предыдущих запросов.

Я прочитал о WITH блок в Postgres, но я не могу понять, как использовать его в моем случае.

UPDATE Я сделал, как предложил:

-- First record -- 
WITH t0 AS (
    WITH t1 AS (
      INSERT INTO subscriber 
      VALUES(DEFAULT, 'Twilight Sparkle', NULL, NULL) 
      RETURNING sub_id 
    ), 
    t2 AS (
      INSERT INTO address 
      VALUES(DEFAULT, 'Equestria', 'Ponyville', NULL, NULL, NULL) 
      RETURNING addr_id 
    ) 
    INSERT INTO sub_link 
    VALUES((SELECT sub_id FROM t1), (SELECT addr_id FROM t2)) 
) 
INSERT INTO phone 
VALUES (DEFAULT, '000000', (SELECT sub_id FROM t1), 1); 

Но у меня есть ошибка: С п, содержащей заявление на данные изменения должны быть на самом высоком уровне ЛИНИЯ 2: С t1 AS (INSERT INTO абонент VALUES (DEFAULT,

ответ

0

У вас возникла идея. Вставьте данные из самых верхних таблиц, чтобы у вас были свои идентификаторы, прежде чем вставлять ссылки на них.

В PostgreSQL вы можете использовать конструкцию INSERT/UPDATE ... RETURNING id. Если вы не используете какой-либо ORM, который делает это автоматически, это может быть полезно.

Единственное здесь является то, что на шаге 2 вы, вероятно, хотите, чтобы проверить, если адрес уже существует перед установкой:

SELECT addr_id FROM address WHERE country = ? AND city = ? ... 
1

Вы можете сделать все это в одном запросе с помощью WITH блока с RETURNING пункта. См. PostgreSQL docs on INSERT.Например:

WITH t1 AS (INSERT INTO subscriber VALUES ... RETURNING sub_id), 
t2 AS (INSERT INTO address VALUES ... RETURNING addr_id) 
INSERT INTO sub_link VALUES ((SELECT sub_id FROM t1), (SELECT addr_id FROM t2)) 

Обратите внимание, что эта простая форма будет работать только при вставке одной строки в каждую таблицу.

Это несколько не соответствует теме вашего вопроса, но я предлагаю вам также рассмотреть возможность создания столбцов sub_id и cat_id в внешних ключах телефонной таблицы (используйте ССЫЛКИ).

+0

Позволяет ли postgres выполнять две последовательности вставки в блоке WITH? Вот так: 'INSERT INTO sub_link VALUES ((SELECT sub_id FROM t1), (SELECT addr_id FROM t2)), INSERT INTO phone VALUES (DEFAULT," 1111111 ", (SELECT sub_id FROM t1), ...' – memset

+0

Конечно, просто поместите все, кроме последнего INSERT, в свой собственный блок WITH. Каждый блок WITH может ссылаться на псевдонимы, которые были перед ним. Например: ... t3 AS (INSERT INTO sub_link VALUES ((SELECT ... FROM t1), ...)) INSERT INTO phone ... ' – ASL

+0

Обновленный исходный пост. Запрос становится очень сложным. Используя вложенный блок' WITH', я получил ошибку. Предложение WITH, содержащее инструкцию для изменения данных, должно быть в верхней части. – memset

Смежные вопросы