2013-07-09 14 views
27

Es ist möglich, löschen-Anweisungen registrieren um den Satz zu qualifizieren gelöscht werden, wie die folgenden:Kann man aus mehreren Tabellen in derselben SQL-Anweisung löschen?

DELETE J 
FROM Users U 
inner join LinkingTable J on U.id = J.U_id 
inner join Groups G on J.G_id = G.id 

WHERE G.Name = 'Whatever' 
and U.Name not in ('Exclude list') 

Jedoch habe ich beim Löschen auf beiden Seiten der Kriterien beitreten interessiert bin - sowohl in der LinkingTable Aufzeichnung und die Benutzerdatensatz, von dem es abhängt. Ich kann Kaskaden nicht einschalten, weil meine Lösung zuerst Entity Framework-Code ist und die bidirektionalen Beziehungen für mehrere Kaskadenpfade sorgen.

Idealerweise würde Ich mag so etwas wie:

DELETE J, U 
FROM Users U 
inner join LinkingTable J on U.id = J.U_id 
... 

syntaktisch dies nicht funktioniert, aber ich bin gespannt, ob so etwas möglich ist?

+3

Nein, eine DML-Anweisung kann nur eine Tabelle betreffen. Ihre Option besteht darin, eine der Einschränkungen zu entfernen (und sie möglicherweise stattdessen mithilfe eines Triggers durchzusetzen). –

+2

Ich denke, Sie müssen in Ihrer Frage deutlicher machen, dass Sie Fremdschlüssel in beide Richtungen zeigen. –

+0

@AaronBertrand: Danke - das war die Antwort, nach der ich gesucht habe: DML-Anweisungen können nur eine Tabelle beeinflussen und somit ist das, was ich will, unmöglich. Wir müssen einen anderen Weg finden. Wenn Sie eine Antwort auf diesen Effekt schreiben, werde ich es markieren. – bwerks

Antwort

33

Nein, Sie müssten mehrere Anweisungen ausführen.

Da müssen Sie aus zwei Tabellen löschen, sollten Sie eine temporäre Tabelle der passenden IDs zu erstellen:

SELECT U.Id INTO #RecordsToDelete 
FROM Users U 
    JOIN LinkingTable J ON U.Id = J.U_Id 
... 

Und dann aus jeder der Tabellen löschen:

DELETE FROM Users 
WHERE Id IN (SELECT Id FROM #RecordsToDelete) 

DELETE FROM LinkingTable 
WHERE Id IN (SELECT Id FROM #RecordsToDelete) 
+0

Ich denke, das Problem ist ein bidirektionaler Fremdschlüssel, in welchem ​​Fall auch getrennte Anweisungen nicht funktionieren (Huhn + Ei). –

+0

Wenn dies der Fall ist, könnte es möglicherweise auch funktionieren, die Einschränkung zu löschen und sie nach den Löschdurchläufen wieder hinzuzufügen. – user2480596

+2

Ich glaube nicht, dass Sie mit EF - Code First Constraints im Handumdrehen deaktivieren/aktivieren können, und dies ist wahrscheinlich in einer Umgebung mit hohem gemeinsamen Zugriff ohnehin nicht die optimale Lösung. Wenn Sie die Beschränkung die ganze Zeit ausschalten, was ist der Sinn daran, es jemals zu aktivieren? –

3

Die Art und Weise Sie sagen ist möglich in MY SQL aber nicht für SQL SERVER

Sie die „gelöscht“ verwenden kann, Pseudo-Tabelle für die Werte aus zwei Tabellen zu einer Zeit, zu löschen wie,

begin transaction; 

declare @deletedIds table (samcol1 varchar(25)); 

delete #temp1 
output deleted.samcol1 into @deletedIds 
from #temp1 t1 
join #temp2 t2 
on t2.samcol1 = t1.samcol1 

delete #temp2 
from #temp2 t2 
join @deletedIds d 
on d.samcol1 = t2.samcol1; 

commit transaction; 

Für kurze Erläuterung können Sie in diesem Link

einen Blick und die Verwendung von Deleted Tabelle wissen Sie das Using the inserted and deleted Tables folgen

+0

Meinten Sie: "Die Art, wie Sie sagen, ist in MY SQL möglich, aber * nicht * für SQL SERVER"? –

+0

@EdwardBrey Ja hatte ich das nur gemeint ... – Rajesh

2

Die einzige Möglichkeit, die ich mir vorstellen konnte ist, brechen Sie die bidirektionale Fremdschlüssel in einem prozeduralen Weg.

Dieser Ansatz kann enorme Auswirkungen auf Ihre Anwendung Seite haben, wenn Sie einige Flags für visualization Zustand nicht haben oder status

So etwas wie

  1. INSERT Dummy nicht sichtbaren Zeilen an Benutzer (mit so etwas wie Id = -1 für Blindwerte)
  2. In den LinkingTable eine alternative Spalte Users Punkt zurück, werde ich es nennen U_ComesFrom

    ALTER TABLE LinkingTagble ADD U_ComesFrom_U_id INT DEFAULT (-1)

  3. hinzufügen FOREIGN KEY mit einem NOCHECK

    ALTER TABLE LinkingTable MIT NOCHECK
    FOREIGN KEY (U_ComesFrom_U_id)
    Informationsquellen Benutzer (Id);

  4. In den Users Spalte

    ALTER TABLE Benutzer MarkedForDeletion BIT NOT NULL DEFAULT (0) in

Dann wird Ihr SQL aussehen würde wie

BEGIN TRANSACTION 
    UPDATE J 
    SET U_Comes_From_U_id = U_ID, U_id = -1 -- or some N/R value that you define in Users 
    FROM Users U 
    inner join LinkingTable J on U.id = J.U_id 
    inner join Groups G on J.G_id = G.id 
    WHERE G.Name = 'Whatever' 
    and U.Name not in ('Exclude list') 

    UPDATE U 
    SET MarkedForDeletion = 1 
    FROM Users 
    inner join LinkingTable J on U.id = J.U_ComesFrom_U_id 
    WHERE U_id > 0 

    DELETE FROM LinkingTable 
    WHERE U_ComesFrom_U_id > 0 

    DELETE FROM Users 
    WHERE MarkedForDeletion = 1 

COMMIT 

Dieser Ansatz der auswirken würde Leistung, da jede Transaktion mindestens 4 DML-Operationen pro bidirektionale Schlüssel wäre.

1

Probieren CATCH mit der Transaktion

BEGIN TRANSACTION 
BEGIN TRY 
    DELETE from A WHERE id=1 

    DELETE FROM b WHERE id=1 

    COMMIT TRANSACTION; 
END TRY 
BEGIN CATCH 
ROLLBACK TRANSACTION; 
END CATCH 

oder Sie können auch Abspeicherprozedur für gleiche Using Stored Procedure With Transaction:

0

verwenden Wenn Sie den Fremdschlüssel durch T-SQL erstellen, müssen Sie die ON anhängen CASCADE DELETE Option zum Fremdschlüssel:

Code Snippet 

ALTER TABLE <tablename> 
ADD CONSTRAINT <constraintname> FOREIGN KEY (<columnname(s)>) 
REFERENCES <referencedtablename> (<columnname(s)>) 

ON DELETE CASCADE; 
Verwandte Themen