Hinzufügen einer Fremdschlüsselbeziehung zwischen zwei Datenbanken

88

Ich habe zwei Tabellen in zwei verschiedenen Datenbanken. In Tabelle1 (in Datenbank1) gibt es eine Spalte namens Spalte1 und es handelt sich um einen Primärschlüssel. Jetzt gibt es in Tabelle2 (in Datenbank2) eine Spalte namens Spalte2 und ich möchte sie als Fremdschlüssel hinzufügen.

Ich habe versucht, es hinzuzufügen, und es gab mir den folgenden Fehler:

Meldung 1763, Ebene 16, Status 0, Zeile 1
Datenbankübergreifende Fremdschlüsselreferenzen werden nicht unterstützt. Fremdschlüssel Database2.table2.

Meldung 1750, Ebene 16, Status 0, Zeile 1 Es
konnte keine Einschränkung erstellt werden. Siehe vorherige Fehler.

Wie mache ich das, da sich die Tabellen in verschiedenen Datenbanken befinden?

Sam
quelle

Antworten:

81

Sie müssten die referenzielle Einschränkung datenbankübergreifend mithilfe eines Triggers verwalten.


Grundsätzlich erstellen Sie einen Einfüge- und Aktualisierungsauslöser, um die Existenz des Schlüssels in der Primärschlüsseltabelle zu überprüfen. Wenn der Schlüssel nicht vorhanden ist, setzen Sie das Einfügen oder Aktualisieren zurück und behandeln Sie die Ausnahme.

Beispiel:

Create Trigger dbo.MyTableTrigger ON dbo.MyTable, After Insert, Update
As
Begin

   If NOT Exists(select PK from OtherDB.dbo.TableName where PK in (Select FK from inserted) BEGIN
      -- Handle the Referential Error Here
   END

END

Bearbeitet: Nur zur Klarstellung. Dies ist nicht der beste Ansatz zur Durchsetzung der referenziellen Integrität. Idealerweise möchten Sie beide Tabellen in derselben Datenbank, aber wenn dies nicht möglich ist. Dann ist das oben Genannte eine mögliche Lösung für Sie.

John Hartsock
quelle
3
@ John Hartsock - Das obige Beispiel kann leicht fehlschlagen, ohne eine entsprechende Transaktionsbehandlung hinzuzufügen. Eine anständige Diskussion über die Art des Problems, das bei "Wenn nicht vorhanden (), dann Einfügen" auftreten kann, finden Sie hier - stackoverflow.com/questions/108403/…
EBarr
14
@ John Hartsock - Ihre Lösung hat eine Lücke: Wenn eine der beiden Datenbanken aus einem Backup wiederhergestellt wird, werden Trigger natürlich nicht ausgelöst. Auf diese Weise können wir verwaiste Zeilen erhalten.
AK
3
@AlexKuznetsov Genau. Wie ich erklärte, ist dies nicht der beste Ansatz, sondern eine mögliche Lösung.
John Hartsock
2
Das ist einfach so falsch ... Ich hoffe nur, dass das OP erkennt, dass nur die Tatsache, dass er nach so etwas fragt, ein Symptom dafür ist, dass er höchstwahrscheinlich etwas falsch macht ... geschweige denn über Auslöser nachdenken ...
MeTitus
1
@Marco Wie ich in meiner Antwort gepostet habe "Nur zur Verdeutlichung. Dies ist nicht der beste Ansatz zur Durchsetzung der referenziellen Integrität. Idealerweise möchten Sie beide Tabellen in derselben Datenbank, aber wenn dies nicht möglich ist. Dann ist das oben Genannte eine mögliche Lösung für Sie." Ich erklärte, dass dies wahrscheinlich keine gute Idee ist.
John Hartsock
47

Wenn Sie eine solide Integrität benötigen, haben Sie beide Tabellen in einer Datenbank und verwenden Sie eine FK-Einschränkung. Wenn sich Ihre übergeordnete Tabelle in einer anderen Datenbank befindet, hindert nichts jemanden daran, diese übergeordnete Datenbank aus einer alten Sicherung wiederherzustellen, und dann haben Sie Waisen.

Aus diesem Grund wird FK zwischen Datenbanken nicht unterstützt.

AK
quelle
27

Nach meiner Erfahrung besteht der beste Weg, dies zu handhaben, wenn sich die primäre maßgebliche Informationsquelle für zwei verwandte Tabellen in zwei separaten Datenbanken befinden muss, darin, eine Kopie der Tabelle vom primären Speicherort zum sekundären Speicherort zu synchronisieren (mithilfe von T- SQL oder SSIS mit entsprechender Fehlerprüfung - Sie können eine Tabelle nicht abschneiden und neu füllen, solange sie eine Fremdschlüsselreferenz enthält. Es gibt also einige Möglichkeiten, die Katze bei der Aktualisierung der Tabelle zu häuten.

Fügen Sie dann der Tabelle eine herkömmliche FK-Beziehung an der zweiten Stelle hinzu, die praktisch eine schreibgeschützte Kopie ist.

Sie können einen Trigger oder einen geplanten Job am primären Speicherort verwenden, um die Kopie auf dem neuesten Stand zu halten.

Cade Roux
quelle
1
Re. "Sie können einen Job am primären Speicherort auslösen oder planen, um die Kopie auf dem neuesten Stand zu halten." muss schreibgeschützt sein)? Siehe: Link
Tom
@ Tom Ja, Sie können sicherlich die Replikation verwenden, um eine Kopie der Tabelle in einer entfernten Datenbank auf dem neuesten Stand zu halten.
Cade Roux
20

Sie können die Prüfbedingung mit einer benutzerdefinierten Funktion verwenden, um die Prüfung durchzuführen. Es ist zuverlässiger als ein Auslöser. Es kann wie Fremdschlüssel deaktiviert und bei Bedarf wieder aktiviert werden und nach einer Datenbank2-Wiederherstellung erneut überprüft werden.

CREATE FUNCTION dbo.fn_db2_schema2_tb_A
(@column1 INT) 
RETURNS BIT
AS
BEGIN
    DECLARE @exists bit = 0
    IF EXISTS (
      SELECT TOP 1 1 FROM DB2.SCHEMA2.tb_A 
      WHERE COLUMN_KEY_1 =  @COLUMN1
    ) BEGIN 
         SET @exists = 1 
      END;
      RETURN @exists
END
GO

ALTER TABLE db1.schema1.tb_S
  ADD CONSTRAINT CHK_S_key_col1_in_db2_schema2_tb_A
    CHECK(dbo.fn_db2_schema2_tb_A(key_col1) = 1)
Camilo J.
quelle
1
Dies ist eine bessere Lösung als die akzeptierte Antwort und Sie können sie auch für mehrere Tabellen
wiederverwenden
3

Die kurze Antwort lautet, dass SQL Server (ab SQL 2008) keine datenbankübergreifenden Fremdschlüssel unterstützt - wie in der Fehlermeldung angegeben.

Während Sie keine deklarative referenzielle Integrität (FK) haben können, können Sie dasselbe Ziel mithilfe von Triggern erreichen. Es ist ein bisschen weniger zuverlässig, weil die Logik, die Sie schreiben, möglicherweise Fehler enthält, aber es wird Sie trotzdem dorthin bringen.

Weitere Informationen finden Sie in den SQL-Dokumenten unter http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx. Welcher Status:

Trigger werden häufig zur Durchsetzung von Geschäftsregeln und Datenintegrität verwendet. SQL Server bietet DRI (Declarative Referential Integrity) über die Tabellenerstellungsanweisungen (ALTER TABLE und CREATE TABLE). DRI bietet jedoch keine datenbankübergreifende referenzielle Integrität. Verwenden Sie zum Erzwingen der referenziellen Integrität (Regeln für die Beziehungen zwischen Primär- und Fremdschlüssel von Tabellen) Primär- und Fremdschlüsseleinschränkungen (die Schlüsselwörter PRIMARY KEY und FOREIGN KEY von ALTER TABLE und CREATE TABLE). Wenn Einschränkungen für die Triggertabelle vorhanden sind, werden diese nach der Ausführung des INSTEAD OF-Triggers und vor der Ausführung des AFTER-Triggers überprüft. Wenn die Einschränkungen verletzt werden, werden die INSTEAD OF-Triggeraktionen zurückgesetzt und der AFTER-Trigger wird nicht ausgeführt (ausgelöst).

Es gibt auch eine OK-Diskussion bei SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135

EBarr
quelle
0

Wie die Fehlermeldung besagt, wird dies auf einem SQL Server nicht unterstützt. Die einzige Möglichkeit, die Integrität der Auffrischung sicherzustellen, besteht darin, mit Triggern zu arbeiten.

Jan.
quelle
1
Können Sie mir ein Beispiel geben
Sam