Чи можу я отримати зовнішній ключ, що посилається на стовпець у поданні в SQL Server?


84

У 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? Чи можна це зробити за допомогою зовнішнього ключа проти точки зору?

Відповіді:


108

Ви не можете вказати подання у зовнішньому ключі.


38
це обмеження SQL-сервера або це нерозумно бажати?
Аарон Анодід

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

4
Це хороша відповідь на ці подальші запитання - stackoverflow.com/questions/3833150/…
Chris Halcrow

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

27

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


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

16

Якщо вам дійсно потрібна A_or_B_IDтаблиця Z, у вас є два схожі варіанти:

1) Додайте до таблиці z нульові значення A_IDта B_IDстовпці, створіть A_or_B_IDобчислюваний стовпець, використовуючи ISNULL для цих двох стовпців, та додайте обмеження CHECK, яке лише одне з A_IDабо B_IDне має значення null

2) Додайте стовпець TableName до таблиці z, обмежений вмістом A або B. Тепер створіть A_IDі B_IDяк обчислювані стовпці, які не є нульовими, лише коли названо відповідну таблицю (з використанням виразу CASE). Зробіть їх також наполегливими

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

(Дякую за коментар за виправлення мого форматування)


Поставте слова з підкресленням у зворотній бік: A_or_B_ID
Білл Карвін,

Я працюю над додаванням деяких функцій до застарілої системи, і це чудовий спосіб поєднати старе та нове. Дякую!
Девід Гундерсон,


4

Є ще один варіант. Розглядайте TableA та TableB як підкласи нової таблиці, яка називається TablePrime. Налаштуйте значення ідентифікатора TableB, щоб вони не збігалися зі значеннями ID TableA. Зробіть ідентифікатор у TablePrime PK і вставте всі ідентифікатори TableA та TableB (скориговані) у TablePrime. Зробіть, щоб TableA та TableB мали зв’язок FK на своєму ПК з однаковим ідентифікатором у TablePrime.

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

Якщо вам потрібні додаткові відомості, будь ласка, запитайте. Є варіанти, які дозволять вам переконатися, що А і В взаємовиключні, або, можливо, річ, з якою ви працюєте, може бути одночасно одночасно. Найкраще це формалізувати у ФК, якщо це можливо.


2

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

Перевагою є те, що він може отримувати кілька стовпців, виконувати з ними обчислення, приймати нулі та приймати значення, які не точно відповідають первинному ключу або порівнювати з результатами об'єднання.

Недоліком є ​​те, що оптимізатор не може використовувати всі свої трюки з іноземними ключами.


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.