SQL — внешний ключ, ссылающийся на первичный ключ разных таблиц (Postgres)

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

Вот что я придумал (имена таблиц не являются их настоящими именами, просто хочу, чтобы они были здесь общими).

Изменить: я использую Postgres

Таблица записей:

recordId -> references record1 id,record2 id,record2 id
docId -> identifies what kind of record it is
filingDate

Запись1:

id
attribute2
attribute3

Запись2:

id
attribute2
attribute3

Запись3:

attribute2
attribute3

На самом деле Record1, Record2 и Record3 имеют более 30 столбцов каждая (представьте, например, свидетельство о рождении).

RecordsTable будет отображаться для пользователей. запись1-3 будет отображаться только в том случае, если пользователю нужно что-то отредактировать.

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

Если есть что-то неясное, пожалуйста, дайте мне знать, чтобы я мог объяснить это подробнее. заранее спасибо


person Jinnean    schedule 10.03.2012    source источник
comment
Должен ли RecordsTable вообще существовать. Разве представление, выполняющее UNION ALL между отдельными таблицами записей (и любыми общими столбцами), не послужит этой цели лучше?   -  person Damien_The_Unbeliever    schedule 10.03.2012
comment
+1 @Damien_The_Unbeliever; с уникальным идентификатором во всех таблицах записей это будет быстро, и запрос будет намного проще.   -  person Ben    schedule 10.03.2012
comment
@Ben - если вы добавите столбец, например. TableName, то комбинация TableName и Id должна быть уникальной без дополнительных усилий.   -  person Damien_The_Unbeliever    schedule 10.03.2012
comment
@Damien_The_Unbeliever, я не подумал об этом. Предполагается, что вы знаете таблицу, из которой должна быть получена запись, в то время, когда вы запрашиваете ее, но это намного, намного проще реализовать...   -  person Ben    schedule 10.03.2012
comment
так что мне действительно нужно объединить всех. Влияет ли это на время выполнения, потому что, как я уже сказал, он будет состоять из 30 или более столбцов и тысяч записей в каждой таблице, и после этого он будет отсортирован по дате подачи? edit: я не видел общие столбцы фразы. Хорошо, тогда да, это действительно легко   -  person Jinnean    schedule 10.03.2012
comment
Если имеет смысл сделать UNION ALL, вы можете также объединить все три таблицы в одну и просто добавить столбец типов. Если у них мало или совсем нет общих столбцов, то объединение тоже не имеет смысла.   -  person alexis    schedule 10.03.2012
comment
Возможно, вам следует сделать резервную копию и описать свое приложение немного подробнее.   -  person alexis    schedule 10.03.2012


Ответы (2)


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

Чтобы id было уникальным в трех таблицах, вам понадобится один столбец identity. (Если вы не используете Oracle или Postgres, если это так, отредактируйте свой вопрос.) Таким образом, пользователи должны будут получить идентификатор записи из таблицы Records, прежде чем они смогут заполнить детали. Возможно, вы можете создать пользовательский интерфейс, который сделает это за них.

RecordsTable: id int identity, filingDate
Record1: id int foreign key references RecordsTable(id), ...
Record2: id int foreign key references RecordsTable(id), ...

Вы получите тип документа, например:

select  case
        when record1.id is not null then 'Type1'
        when record2.id is not null then 'Type2'
        ...
        else 'Unknown'
        end
from    RecordsTable rt
left join
        Record1 r1
on      rt.id = r1.id
left join
        Record2 r2
on      rt.id = r2.id
person Andomar    schedule 10.03.2012
comment
В Postgres вы можете использовать последовательность для создания уникального идентификатора. . Это позволяет вам сделать запись RecordTable необязательной, хотя я бы не рекомендовал это делать. - person Andomar; 10.03.2012

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

Если вам нужно, чтобы ваша основная таблица ссылалась на любую из трех разных таблиц (и они имеют такие разные столбцы, что вы не можете объединить их в одну таблицу), настройте свою основную таблицу следующим образом:

RecordsTable:
Id -> primary key for the table
docType -> identifies what kind of record it is: 1, 2, or 3
docID1 -> Foreign key to table1, if docType = 1; NULL otherwise
docID2 -> Foreign key to table2, if docType = 2; NULL otherwise
docID3 -> you get the idea
filingDate

Но если у вас есть три вида сущностей с очень разным содержанием, нужно ли вам перечислять их все вместе? Возможно, на самом деле это не так, и в этом случае вы можете просто поддерживать их как отдельные таблицы. Если имеет смысл перечислить их все вместе, у вас есть концептуально одна сущность («документ», как это звучит) с тремя подтипами. Возможно, имеет смысл упростить себе задачу и хранить их в одной таблице с большим количеством пустых столбцов (столбцы VARCHAR не занимают места, когда они пусты). Это немного расточительно, но в современных компьютерах есть свободное место и мощность, а ваше время ценно. Но вы возражаете,

Это просто показать сводку всех записей, хранящихся в офисе, так как показывать все сразу будет нехорошо.

Это не проблема! Выполните запрос SELECT только со столбцами, которые вы хотите отобразить для сводки. Если пользователь выбирает запись, выполните SELECT * и покажите полный результат.

Если вы хотите потрудиться, разделив нестандартные поля, сделайте это, как описано выше.

По сути, вам нужно немного программировать. Не думайте о своей базе данных как о всей программе: задача базы данных — хранить данные, работа приложения — что-то с ними делать.

person alexis    schedule 10.03.2012
comment
@Jinnean Это, вероятно, сработает, но имхо это не очень деликатное решение. Будет больно поддерживать вашу таблицу записей. С некоторым изменением дизайна вы можете удалить RecordsTable из своей базы данных. - person supertopi; 10.03.2012
comment
@alexis да, я знаю, что пользователь не должен об этом беспокоиться, поэтому я отказался от этой идеи и ищу другую. Хотя ваш ответ - один из ответов, о которых я подумал, но внешний ключ не должен быть нулевым, верно? и если это действительно то, что мне нужно сделать, то я должен присоединиться к этим трем столам - person Jinnean; 10.03.2012
comment
@supertopi Я также подумал о том, чтобы выбросить таблицу записей и просто получить все идентификаторы, упорядочить их по дате подачи, а затем показать пользователю. но это означало бы, что я должен время от времени присоединяться ко всем таблицам и сортировать их по дате подачи. - person Jinnean; 10.03.2012
comment
Я полагаю, это зависит от вашей СУБД, но внешние ключи могут быть нулевыми. Первичные ключи не могут (на самом деле я думаю, что в некоторых СУБД они могут, но это не имеет смысла) - person alexis; 10.03.2012