Можно ли наложить ограничение на столбец, не ссылаясь на другую таблицу? - PullRequest
2 голосов
/ 30 августа 2009

У меня есть текстовый столбец, который должен содержать только 1 из 3 возможных строк. Чтобы наложить на это ограничение, мне нужно сослаться на другую таблицу. Могу ли я вместо этого поместить значения ограничения непосредственно в столбец, не обращаясь к другой таблице?

Ответы [ 3 ]

5 голосов
/ 30 августа 2009

Если это SQL Server , Oracle или PostgreSQL , да, вы можете использовать check constraint.

Если это MySQL, check constraint s распознаются, но не применяются. Вы можете использовать enum, хотя. Если вам нужен список через запятую, вы можете использовать set.

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

3 голосов
/ 30 августа 2009

В дополнение к ограничению CHECK и типу данных ENUM, которые упоминаются в других источниках, вы также можете написать триггер, чтобы применить желаемое ограничение.

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

Моя привычка - определять таблицы поиска вместо использования ограничений или триггеров, когда правило состоит в том, чтобы просто ограничить столбец конечным набором значений. Влияние на производительность проверки по справочной таблице ничуть не хуже, чем использование ограничений или триггеров CHECK, и намного проще управлять, когда набор значений может время от времени меняться.

Также обычной задачей является запрос набора разрешенных значений, например, для заполнения поля формы в пользовательском интерфейсе. Когда разрешенные значения находятся в таблице поиска, это намного проще, чем когда они определены в списке литеральных значений в ограничении CHECK или определении ENUM.


Комментарий: «Как сделать поиск без идентификатора»

CREATE TABLE LookupStrings (
  string VARCHAR(20) PRIMARY KEY
);

CREATE TABLE MainTable (
  main_id INT PRIMARY KEY,
  string VARCHAR(20) NOT NULL,
  FOREIGN KEY (string) REFERENCES LookupStrings (string)
);

Теперь вы можете быть уверены, что никакое значение в MainTable.string недопустимо, так как ссылочная целостность предотвращает это. Но вам не нужно присоединяться к таблице LookupStrings, чтобы получить строку, когда вы запрашиваете MainTable:

SELECT main_id, string FROM MainTable;

См? Не присоединяйтесь! Но вы получите строковое значение.


Комментарий к нескольким столбцам внешнего ключа:

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

Мой типичный пример - база данных отслеживания ошибок, в которой один пользователь сообщил об ошибке, но назначил ее для исправления другим пользователем. И reported_by, и assigned_to являются внешними ключами, ссылающимися на таблицу Accounts.

CREATE TABLE Bugs (
  bug_id INT PRIMARY KEY,
  reported_by INT NOT NULL,
  assigned_to INT,
  FOREIGN KEY (reported_by) REFERENCES Accounts (account_id),
  FOREIGN KEY (assigned_to) REFERENCES Accounts (account_id)
);
2 голосов
/ 30 августа 2009

В Oracle, SQL Server и PostgreSQL, используйте ограничение CHECK.

CREATE TABLE mytable (myfield INT VARCHAR(50) CHECK (myfield IN ('first', 'second', 'third'))

В MySQL, используйте ENUM тип данных:

CREATE TABLE mytable (myfield ENUM ('first', 'second', 'third'))
...