Posso avere una chiave esterna che fa riferimento a una colonna in una vista in SQL Server?


85

In SQL Server 2008 e dato

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

è possibile definire TableZ(A_or_B_ID, Z_Data)tale che la Z.A_or_B_IDcolonna sia vincolata ai valori trovati in ViewC? Può essere fatto con una chiave esterna contro la vista?

Risposte:


110

Non puoi fare riferimento a una vista in una chiave esterna.


38
è una limitazione dell'assistente SQL o è una cosa irragionevole desiderare?
Aaron Anodide

1
@Brian Anch'io sarei interessato a sapere se questa è una limitazione di SQL Server o una cosa irragionevole da volere perché a questo punto sto per emulare una vista usando i trigger solo per ottenere supporto FK (anche se sto usando MySql ).
Slitta

4
Questa è una buona risposta a queste domande di follow-up - stackoverflow.com/questions/3833150/…
Chris Halcrow

Non sono sicuro di come sia una buona risposta a queste domande ... si tratta di un diverso DBMS e dice che le visualizzazioni sono state progettate per nascondere i dettagli dello schema e la comodità dell'utente. Innanzitutto, ok ... ma questa non sarebbe la prima cosa in assoluto a trovare casi d'uso solidi oltre il design iniziale. In secondo luogo, non sono sicuro del motivo per cui un FK non lo farebbe. Una vista può essere qualsiasi query che non deve nemmeno estrarre da una tabella, può essere un gruppo di costanti unite insieme ... una chiave esterna sembra davvero sensata in quel caso. Se c'è un motivo per cui no, spero in qualcosa di più profondo.
George Mauer

27

Nelle edizioni precedenti di SQL Server le chiavi esterne erano possibili solo tramite trigger. Puoi imitare una chiave esterna personalizzata creando un trigger di inserimento che controlla se il valore inserito appare anche in una delle tabelle pertinenti.


3
benvenuto in StackOverflow. Ho trovato valore nella tua risposta poiché fornisce una soluzione alternativa, ma la risposta corretta è quella accettata e la domanda ha più di 4 anni, quindi non voterò ma non volevo lasciare questo commento.
jachguate

16

Se hai davvero bisogno A_or_B_IDdi TableZ, hai due opzioni simili:

1) Aggiungi nullable A_IDe B_IDcolonne alla tabella z, crea A_or_B_IDuna colonna calcolata usando ISNULL su queste due colonne e aggiungi un vincolo CHECK in modo tale che solo uno di A_IDo B_IDnon sia nullo

2) Aggiungere una colonna TableName alla tabella z, vincolata a contenere A o B. ora creare A_IDe B_IDcome colonne calcolate, che sono solo non nulle quando viene denominata la tabella appropriata (utilizzando l'espressione CASE). Falli persistere anche tu

In entrambi i casi, ora hai A_IDe B_IDcolonne che possono avere chiavi esterne appropriate per le tabelle di base. La differenza è in quali colonne vengono calcolate. Inoltre, non è necessario TableName nell'opzione 2 sopra se i domini delle 2 colonne ID non si sovrappongono, a condizione che l'espressione del tuo caso possa determinare in quale dominio A_or_B_ID rientra

(Grazie al commento per aver corretto la mia formattazione)


Metti le parole con trattini bassi in back-tick: A_or_B_ID
Bill Karwin

Sto lavorando per aggiungere alcune funzionalità a un sistema legacy e questo è un ottimo modo per applicare patch insieme al vecchio e al nuovo. Grazie!
David Gunderson

8

Spiacenti, non è possibile passare a una visualizzazione in SQL Server.


4

C'è un'altra opzione. Considera TableA e TableB come sottoclassi di una nuova tabella denominata TablePrime. Regola i valori ID di TableB in modo che non coincidano con i valori ID di TableA. Rendi l'ID in TablePrime il PK e inserisci tutti gli ID di TableA e TableB (regolati) in TablePrime. Fare in modo che TableA e TableB abbiano relazioni FK sulla loro PK con lo stesso ID in TablePrime.

Ora hai il modello supertipo / sottotipo e puoi creare vincoli a TablePrime (quando vuoi -A-o-B ) o una delle singole tabelle (quando vuoi solo A o solo B ).

Se hai bisogno di maggiori dettagli, chiedi. Ci sono variazioni che ti permetteranno di assicurarti che A e B si escludano a vicenda, o forse la cosa su cui stai lavorando può essere entrambe allo stesso tempo. È meglio formalizzarlo negli FK, se possibile.


2

È più semplice aggiungere un vincolo che fa riferimento a una funzione definita dall'utente che esegue il controllo per te, fCheckIfValueExists (columnValue) che restituisce true se il valore esiste e false se non lo è.

Il vantaggio è che può ricevere più colonne, eseguire calcoli con esse, accettare valori nulli e accettare valori che non corrispondono esattamente a una chiave primaria o confrontare con i risultati dei join.

Lo svantaggio è che l'ottimizzatore non può utilizzare tutti i suoi trucchi con le chiavi esterne.


1
Lo svantaggio è che l'ottimizzatore non può usare tutti i suoi trucchi per le chiavi esterne ... ... e che la funzione verrà eseguita per ogni riga che inserisci / aggiorni (quindi non troppo bello per i set).
jimbobmcgee

1

Spiacenti, nel senso stretto della parola, no, non è possibile impostare chiavi esterne sulle viste. Ecco perché:

InnoDB è l'unico motore di archiviazione integrato per MySQL che dispone di chiavi esterne. Qualsiasi tabella InnoDB verrà registrata in information_schema.tables con engine = 'InnoDB'.

Le viste, sebbene registrate in information_schema.tables, hanno un motore di archiviazione NULL. Non ci sono meccanismi in MySQL per avere chiavi esterne su qualsiasi tabella che abbia un motore di archiviazione non definito.

Grazie!


questa domanda riguarda il server sql
George Mauer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.