Перенос устаревшей таблицы в нормализованную структуру данных с использованием внешних ключей в Oracle SQL - PullRequest
0 голосов
/ 04 марта 2019

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

Я сделал таблицу author, используя:

CREATE TABLE AUTHORS 
AS SELECT AUTHOR_NAME, AUTHOR_SURNAME, AUTHOR_BIRTHDATE

Если я теперь хочу переделать таблицу book, как мне добавить внешний ключ, чтобы автор каждой книгибудет правильным?То есть, если первая запись в исходной таблице book была:

ISBN1 Title1 Author_Name1 Author_Surname1 Author_Birthdate1

Как импортировать эти данные в новую таблицу, чтобы поле нового автора, внешний ключ, ссылалось на правильную записьв таблице автора?Извините, если это сбивает с толку.

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Вы хотите разделить существующую таблицу на две таблицы, одну для хранения авторов, а другую для книг.Чтобы это работало правильно, вам нужно создать уникальный идентификатор для каждого автора.Вот пошаговый подход.


Предполагая следующую унаследованную структуру данных:

create table old_books (
    isbn             NUMBER(13, 0),
    title            VARCHAR2(200),
    author_name      VARCHAR2(200),
    author_surname   VARCHAR2(200),
    author_birthdate DATE
);

И этот пример данных:

         ISBN | TITLE  | AUTHOR_NAME | AUTHOR_SURNAME | AUTHOR_BIRTHDATE
------------: | :----- | :---------- | :------------- | :---------------
1000000000001 | book 1 | name 1      | surname 1      | 01-MAR-90       
1000000000002 | book 2 | name 2      | surname 2      | 01-MAR-95       
1000000000003 | book 3 | name 1      | surname 1      | 01-MAR-90       

Сначала давайте создадим и передадим новую структуру данных для authors (обратите внимание, что вы не хотите использовать CREATE TABLE AS SELECT ..., потому что это не позволяет добавлять ограничения или другие полезные опции).

Чтобы сгенерировать уникальный идентификатор автора, мы используем функцию IDENTITY (доступна начиная с Oracle 12c - без этой функции нам потребуется создать последовательность и триггер).

В устаревшемДанные, мы предполагаем, что каждый автор уникально идентифицируется по его имени, фамилии и дате рождения:

CREATE TABLE authors (
    id         NUMBER GENERATED ALWAYS AS IDENTITY,
    name       VARCHAR2(200),
    surname    VARCHAR2(200),
    birthdate  DATE,
    PRIMARY KEY (id)
);

INSERT INTO AUTHORS (name, surname, birthdate)
SELECT DISTINCT author_name, author_surname, author_birthdate FROM old_books;

2 rows affected

SELECT * FROM authors;

ID | NAME   | SURNAME   | BIRTHDATE
-: | :----- | :-------- | :--------
 1 | name 1 | surname 1 | 01-MAR-90
 2 | name 2 | surname 2 | 01-MAR-95

С этой первой таблицей мы можем теперь создать таблицу books.Он содержит внешний ключ, который ссылается на первичный ключ таблицы authors.Чтобы заполнить таблицу, нам нужно объединить устаревшую таблицу с новой таблицей authors, чтобы восстановить идентификатор каждого автора:

CREATE TABLE books (
    isbn       NUMBER(13, 0),
    title      VARCHAR2(200),
    author_id  NUMBER,
    CONSTRAINT book_author FOREIGN KEY(author_id) REFERENCES authors(id),
    PRIMARY KEY (isbn)
);

INSERT INTO books(isbn, title, author_id)
SELECT ob.isbn, ob.title, a.id
FROM old_books ob
INNER JOIN authors a 
    ON  a.name = ob.author_name
    AND a.surname = ob.author_surname
    AND a.birthdate = ob.author_birthdate;

3 rows affected

SELECT * FROM books;

         ISBN | TITLE  | AUTHOR_ID
------------: | :----- | --------:
1000000000001 | book 1 |         1
1000000000002 | book 2 |         2
1000000000003 | book 3 |         1

Все готово!Данные правильно распределены между двумя таблицами с соответствующими ограничениями.Мы можем объединить обе таблицы с помощью запроса:

SELECT b.isbn, b.title, a.name, a.surname, a.birthdate
FROM authors a
INNER JOIN books b ON a.id = b.author_id;

         ISBN | TITLE  | NAME   | SURNAME   | BIRTHDATE
------------: | :----- | :----- | :-------- | :--------
1000000000001 | book 1 | name 1 | surname 1 | 01-MAR-90
1000000000002 | book 2 | name 2 | surname 2 | 01-MAR-95
1000000000003 | book 3 | name 1 | surname 1 | 01-MAR-90
0 голосов
/ 05 марта 2019

Вы говорите, что имя автора плюс фамилия являются первичным ключом таблицы вашего автора.Это правильный подход.В случае двух авторов с одним и тем же именем вам нужно найти решение, например «Джон» + «Смит» и «Джон Р.».+ «Смит» или «Джон» + «Смит (автор фантазии)».Это называется естественным составным ключом, хотя и не идеальным, поскольку нам, возможно, придется иметь дело с повторяющимися именами, как уже упоминалось.С другой стороны, существует существует авторов с таким именем, поэтому мы можем сразу же столкнуться с этой проблемой; -)

Книги идентифицируются по их ISBN, что делает еще более естественный ключпотому что не может быть дубликатов.(Только если вы хотите добавить очень старые книги или книги, продающиеся на рынке, которые не имеют ISBN, вам нужно создать поддельный ISBN.)

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

CREATE TABLE books AS SELECT isbn, title, author_name, author_surname FROM old_table;
ALTER TABLE books ADD CONSTRAINT fk_book_author FOREIGN KEY (author_name, author_surname)
                                                REFERENCES authors (author_name, author_surname);

Альтернативой может быть введение суррогатных (то есть технических) ключей.Вы должны сгенерировать идентификатор (номер) для каждой книги и каждого автора и работать с ними.(Это означает, что таблица book будет содержать author_id.) Но для хорошей базы данных вы все равно должны подумать о том, что идентифицирует строку естественным образом.Это облегчает работу людей, которые пишут запросы позже.(Например, кто-то просит выбрать список авторов и количество книг, которые они написали. Как написать этот запрос? Достаточно ли указать имя и фамилию или мы можем в итоге получить две строки «Джон Смит | 5» и «Джон Смит | 2 "и исследователь спрашивают, что они не могут использовать этот неоднозначный результат?) Даже при предоставлении суррогатных ключей у вас все равно должно быть уникальное ограничение на естественный ключ, если он есть.Для книг с дополнительными номерами ISBN это может быть название + author_id, а для авторов это может быть имя + фамилия + дата рождения.

Кстати: существуют книги с несколькими авторами; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...