2013-07-09 30 views
27

Có thể xóa bằng cách sử tham gia báo cáo để đủ điều kiện tập bị xóa, chẳng hạn như sau:Có thể xóa từ nhiều bảng trong cùng một câu lệnh SQL không?

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') 

Tuy nhiên tôi quan tâm đến việc xóa cả hai bên trong những tiêu chí tham gia - cả hai kỷ lục LinkingTable và Hồ sơ người dùng mà nó phụ thuộc vào nó. Tôi không thể biến tầng trên bởi vì giải pháp của tôi là mã khung Entity đầu tiên và các mối quan hệ hai chiều tạo ra cho nhiều đường dẫn xếp tầng.

Lý tưởng nhất, tôi muốn một cái gì đó như:

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

Cú pháp này không làm việc ra, nhưng tôi tò mò nếu một cái gì đó như thế này là có thể?

+3

Không, câu lệnh DML chỉ có thể ảnh hưởng đến một bảng. Tùy chọn của bạn là xóa một trong các ràng buộc (và có khả năng thực thi nó bằng cách sử dụng một kích hoạt thay thế). –

+2

Tôi nghĩ rằng bạn cần phải làm cho nó rõ ràng hơn trong câu hỏi của bạn rằng bạn có chìa khóa nước ngoài chỉ trong cả hai hướng. –

+0

@AaronBertrand: Cảm ơn - đó là câu trả lời tôi đang tìm kiếm: Các câu lệnh DML chỉ có thể ảnh hưởng đến một bảng, và do đó những gì tôi muốn là không thể. Chúng ta sẽ phải tìm ra cách khác. Nếu bạn viết câu trả lời cho hiệu ứng đó, tôi sẽ đánh dấu nó. – bwerks

Trả lời

33

Không, bạn cần chạy nhiều câu lệnh.

Bởi vì bạn cần phải xoá từ hai bảng, hãy cân nhắc tạo một bảng temp của id khớp:

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

Và sau đó xóa từ mỗi bảng:

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

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

Tôi nghĩ rằng vấn đề là một khóa ngoại hai chiều, trong trường hợp các câu lệnh riêng biệt sẽ không hoạt động (gà + trứng). –

+0

Nếu đó là trường hợp, sau đó có lẽ bỏ ràng buộc và thêm nó trở lại sau khi xóa chạy có thể làm việc là tốt. – user2480596

+2

Tôi không nghĩ rằng EF - Code First cho phép bạn vô hiệu hóa/bật các ràng buộc khi đang bay, và nó có lẽ không phải là giải pháp tối ưu trong môi trường đồng thời cao. Nếu bạn định tắt giới hạn mọi lúc, thì điểm nào trong việc bật tính năng này? –

3

Cách bạn nói có thể ở MY SQL nhưng không cho SQL SERVER

Bạn có thể sử dụng "đã xóa" bảng giả để xóa các giá trị từ hai bảng tại một thời điểm như thế nào,

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; 

Đối với Giải thích ngắn gọn, bạn có thể có một cái nhìn tại này Link

và biết việc sử dụng Deleted Bảng bạn có thể làm theo Using the inserted and deleted Tables này

+0

Ý của bạn là "Cách bạn nói là có thể trong MY SQL nhưng * không * cho SQL SERVER"? –

+0

@EdwardBrey Có, tôi đã có nghĩa là chỉ ... – Rajesh

2

Cách duy nhất tôi có thể nghĩ là phá vỡ một cách hợp lý các khóa ngoại hai hướng theo cách thủ tục.

Cách tiếp cận này có thể có tác động rất lớn sang một bên ứng dụng của bạn nếu bạn không có một số lá cờ cho visualization tiểu bang hoặc status

Something như

  1. INSERT giả không hàng có thể nhìn thấy Người dùng (với cái gì đó như Id = -1 cho các giá trị giả)
  2. Thêm vào LinkingTable một cột thay thế để quay lại Users, tôi sẽ gọi nó là U_ComesFrom

    ALTER TABLE ADD LinkingTagble U_ComesFrom_U_id INT DEFAULT (-1)

  3. Thêm FOREIGN KEY với một NOCHECK

    ALTER TABLE LinkingTable VỚI nocheck
    KEY NƯỚC NGOÀI (U_ComesFrom_U_id)
    THAM KHẢO Người dùng (Id);

  4. Thêm vào Users cột

    ALTER TABLE Users ADD MarkedForDeletion BIT KHÔNG DEFAULT NULL (0)

Sau đó SQL của bạn sẽ trông như thế

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 

Cách tiếp cận này sẽ ảnh hưởng đến hiệu suất từ ​​mỗi giao dịch sẽ có ít nhất 4 hoạt động DML cho mỗi khóa hai chiều.

1

Sử dụng CATCH TRY với giao dịch

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 

hoặc bạn cũng có thể sử dụng thủ tục Store cho cùng Using Stored Procedure With Transaction:

0

Nếu bạn đang tạo phím nước ngoài thông qua T-SQL bạn phải gắn ON DELETE CASCADE tùy chọn cho khóa ngoài:

Code Snippet 

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

ON DELETE CASCADE; 
Các vấn đề liên quan