2011-11-24 73 views
23

Tôi sẽ xóa dữ liệu trong bảng SQL Server (cấp độ gốc) có mối quan hệ với bảng khác (con).
Tôi đã thử truy vấn Xóa cơ bản. Nhưng nó không hoạt động (và tôi biết nó sẽ không).Xóa dữ liệu bằng khóa ngoài trong bảng SQL Server

DELETE FROM table WHERE ... 

Nó trở sau lỗi

Câu lệnh DELETE mâu thuẫn với các hạn chế THAM KHẢO ...

tôi cần phải giữ schema của bảng. Tôi biết rằng tôi chỉ cần thêm một số từ trong truy vấn, tôi đã từng làm điều này trước đây, nhưng tôi không thể nhớ lại nó.

Trả lời

12

Nếu bạn muốn xóa tự động, bạn cần phải thay đổi lược đồ để ràng buộc khóa ngoài là ON DELETE CASCADE.

Để biết thêm thông tin, hãy xem MSDN page on Cascading Referential Integrity Constraints.

ETA (sau khi làm rõ từ áp phích): Nếu bạn không thể cập nhật giản đồ, trước tiên bạn phải xóa thủ công các bản ghi con bị ảnh hưởng.

+0

ah. Tôi đã bỏ lỡ phần đó trong bài viết của mình, tôi phải làm cho nó hoạt động mà không thay đổi lược đồ. nó có thể đúng không? – Andha

+1

Không, không thể thực hiện với một số truy vấn ma thuật OPTION hoặc bất kỳ thứ gì. Bạn cần phải thực hiện xóa theo cách thủ công. –

28

Bạn có thể vô hiệu hóa và kích hoạt lại các ràng buộc khoá ngoại trước và sau khi xóa:

alter table MyOtherTable nocheck constraint all 
delete from MyTable 
alter table MyOtherTable check constraint all 
+5

Nếu bạn tắt rồi bật lại các ràng buộc, sẽ không bật lại được do tham chiếu 'khóa ngoại 'bị hỏng? –

+0

Không, nó chỉ kiểm tra ràng buộc khi bạn viết giá trị mới vào một trường - nó không quét lại toàn bộ bảng khi bạn đặt lại séc. –

+3

Vâng. Điều này có nghĩa là tất cả dữ liệu trong bảng con sẽ vẫn ở đó. Tôi sắp xóa 2k hàng và tôi nghĩ rằng nó sẽ cồng kềnh nếu tôi giữ dữ liệu trong bảng con. Tôi nghĩ tôi sẽ làm điều đó một cách thủ công. Thx anyway cho những người trả lời. Bạn xứng đáng +1 :) – Andha

2

Vì vậy, bạn cần phải DELETE hàng liên quan từ các bảng mâu thuẫn hoặc logic hơn để UPDATE cột FOREIGN KEY của họ để tham khảo khác PRIMARY KEY từ bảng cha.

Ngoài ra, bạn có thể muốn đọc bài viết này Don’t Delete – Just Don’t

26

Bạn cần xóa thủ công các con. các <condition> là như nhau cho cả hai truy vấn.

DELETE FROM child 
FROM cTable AS child 
INNER JOIN table AS parent ON child.ParentId = parent.ParentId 
WHERE <condition>; 

DELETE FROM parent 
FROM table AS parent 
WHERE <condition>; 
+0

Hai DELETE này có thể được kết hợp theo cách mà tôi chỉ phải viết phần một lần không? –

+1

Tôi không tin như vậy @ThomasTempelmann. Nếu bạn chỉ muốn viết điều kiện một lần, bạn phải bật các lần xóa tầng thay vì xử lý thủ công với mỗi bảng. Câu trả lời của Alastair Maw cũng đề cập đến tùy chọn này. –

2

Để xóa dữ liệu từ các bảng có mối quan hệ của parent_child, Trước tiên, bạn phải xóa dữ liệu từ bảng con bằng cách đề cập join sau đó bạn chỉ cần xóa dữ liệu từ bảng phụ huynh, ví dụ được đưa ra dưới đây:

DELETE ChildTable 
FROM ChildTable inner join ChildTable on PParentTable.ID=ChildTable.ParentTableID 
WHERE <WHERE CONDITION> 


DELETE ParentTable 
WHERE <WHERE CONDITION> 
+0

Đây là câu trả lời hay nhất nếu bạn không xếp tầng xóa. Con trỏ thực hiện khủng khiếp và loại bỏ các ràng buộc để xóa có thể để lại các hàng mồ côi trong các bảng khác. – Corv1nus

5

đây bạn đang thêm chìa khóa ngoại cho bảng "Child" của bạn

ALTER TABLE child 
ADD FOREIGN KEY (P_Id) 
REFERENCES parent(P_Id) 
ON DELETE CASCADE 
ON UPDATE CASCADE; 

Sau đó nếu bạn thực hiện một truy vấn DELETE trên bàn "Cha mẹ" như thế này

DELETE FROM parent WHERE ..... 

kể từ khi đứa trẻ có một tham chiếu đến mẹ với CASCADE DELETE, các "Child" hàng cũng sẽ bị xóa! cùng với "cha mẹ".

1

hữu ích kịch bản mà bạn có thể xóa tất cả dữ liệu trong tất cả các bảng của cơ sở dữ liệu, thay thế tt với bạn tên databse:

declare @tablename nvarchar(100) 
declare c1 cursor for 
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG='tt' AND TABLE_TYPE='BASE TABLE' 

open c1 
fetch next from c1 into @tablename 

while @@FETCH_STATUS = 0 
    begin 
    print @t1 
     exec('alter table ' + @tablename + ' nocheck constraint all') 
     exec('delete from ' + @tablename) 
     exec ('alter table ' + @tablename + ' check constraint all') 
     fetch next from c1 into @tablename 
    end 
close c1 
DEALLOCATE c1 
Các vấn đề liên quan