Могу ли я иметь внешний ключ, ссылающийся на столбец в представлении в SQL Server?


85

В SQL Server 2008 и учитывая

TableA(A_ID, A_Data)
TableB(B_ID, B_Data)
ViewC(A_or_B_ID, A_or_B_Data)

Можно ли определить так TableZ(A_or_B_ID, Z_Data), чтобы Z.A_or_B_IDстолбец ограничивался значениями, найденными в ViewC? Можно ли это сделать с внешним ключом против представления?

Ответы:


110

Вы не можете ссылаться на представление во внешнем ключе.


38
это ограничение SQL-сервера или желать этого неразумно?
Аарон Анодид

1
@Brian Мне тоже было бы интересно узнать, является ли это ограничением SQL Server или необоснованным желанием, потому что на этом этапе я собираюсь эмулировать представление, используя триггеры, просто чтобы получить поддержку FK (хотя я использую MySql ).
Sled

4
Это хороший ответ на следующие вопросы - stackoverflow.com/questions/3833150/…
Крис Хэлкроу

Я не уверен, насколько это хороший ответ на эти вопросы ... он о другой СУБД и говорит, что представления были разработаны для сокрытия деталей схемы и удобства пользователя. Во-первых, хорошо ... но это не первое, что можно найти в надежных сценариях использования за пределами первоначального дизайна. Во-вторых, я не уверен, почему ФК этого не сделает. Представлением может быть любой запрос, который ему даже не нужно извлекать из таблицы, это может быть набор констант, объединенных вместе ... внешний ключ в этом случае кажется чертовски разумным. Если есть причина, почему бы и нет, я бы надеялся на что-то более глубокое.
Джордж Мауэр

27

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


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

16

Если вам действительно нужен A_or_B_IDTableZ, у вас есть два похожих варианта:

1) Добавьте в таблицу z столбцы, допускающие значение NULL, A_IDи B_IDстолбцы, создайте A_or_B_IDвычисляемый столбец с использованием ISNULL для этих двух столбцов и добавьте ограничение CHECK, чтобы только один из A_IDили B_IDне был нулевым

2) Добавьте столбец TableName в таблицу z, который должен содержать либо A, либо B. Теперь создайте A_IDи B_IDкак вычисляемые столбцы, которые не равны NULL, только если их соответствующая таблица названа (с использованием выражения CASE). Сделайте так, чтобы они тоже остались

В обоих случаях, теперь у вас есть , A_IDи B_IDстолбцы , которые могут иметь соответствующие внешние ключи к базовым таблицам. Разница в том, какие столбцы вычисляются. Кроме того, вам не нужно TableName в варианте 2 выше, если домены двух столбцов идентификатора не перекрываются - если ваше выражение case может определить, какой домен A_or_B_ID попадает в

(Спасибо за комментарий за исправление моего форматирования)


Поместите слова с подчеркиванием в обратные галочки: A_or_B_ID
Билл Карвин,

Я работаю над добавлением некоторых функций в устаревшую систему, и это отличный способ исправить старые и новые вместе. Спасибо!
Дэвид Гандерсон


4

Есть еще вариант. Рассматривайте TableA и TableB как подклассы новой таблицы с именем TablePrime. Настройте значения идентификатора TableB так, чтобы они не совпадали со значениями идентификатора TableA. Сделайте идентификатор в TablePrime PK и вставьте все (скорректированные) идентификаторы TableA и TableB в TablePrime. Сделайте так, чтобы TableA и TableB имели отношения FK на их PK с одним и тем же идентификатором в TablePrime.

Теперь у вас есть шаблон супертипа / подтипа, и вы можете наложить ограничения на TablePrime (когда вы хотите -A -или-B ) или одну из отдельных таблиц (когда вы хотите только A или только B ).

Если вам нужна более подробная информация, спрашивайте. Существуют варианты, которые позволят вам убедиться, что A и B являются взаимоисключающими, или, возможно, то, с чем вы работаете, может быть обоими одновременно. По возможности лучше формализовать это в ФК.


2

Проще добавить ограничение, которое ссылается на пользовательскую функцию, которая выполняет проверку за вас, fCheckIfValueExists (columnValue), которая возвращает истину, если значение существует, и ложь, если нет.

Положительным моментом является то, что он может получать несколько столбцов, выполнять с ними вычисления, принимать нули и принимать значения, которые не точно соответствуют первичному ключу или сравниваются с результатами объединений.

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


1
Обратной стороной является то, что оптимизатор не может использовать все свои уловки с внешним ключом ... ... и что функция будет запускаться для каждой строки, которую вы вставляете / обновляете (что не очень хорошо для наборов).
jimbobmcgee

1

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

InnoDB - единственный встроенный механизм хранения MySQL, который имеет внешние ключи. Любая таблица InnoDB будет зарегистрирована в information_schema.tables с помощью engine = 'InnoDB'.

Представления, зарегистрированные в information_schema.tables, имеют механизм хранения NULL. В MySQL нет механизмов, позволяющих иметь внешние ключи в любой таблице с неопределенным механизмом хранения.

Благодаря!


этот вопрос касается сервера sql
Джордж Мауэр
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.