2010-07-22 23 views
32

Tôi có hai bảng (Nhiệm vụ và Timeentries), được nối với nhau bằng một khóa ngoại (TimeEntries.TaskID tham chiếu Tasks.ID)cách thanh lịch để xóa hàng mà không được tham chiếu bởi bảng khác

Bây giờ tôi muốn để xóa tất cả các hàng khỏi các Tác vụ không được tham chiếu bởi bảng TimeEntries. Tôi nghĩ rằng điều này sẽ hoạt động:

DELETE FROM Tasks WHERE ID not IN (SELECT TaskID FROM TimeEntries) 

Nhưng nó ảnh hưởng đến 0 hàng, mặc dù có rất nhiều hàng không được trả lời trong bảng Tác vụ.

Điều gì có thể là vấn đề ở đây? Tất nhiên tôi có thể viết một SP mà lặp tất cả các hàng, nhưng có vẻ như điều này có thể được thực hiện trong một lớp lót.

Tôi đoán đây là một trong những lỗi tràn bộ lọc theo thời gian. Hãy giúp tôi!

+2

Bạn có nhận được kết quả mong đợi nếu bạn chỉ chạy truy vấn con SELECT không? – JNK

+0

@ J-N-K: vâng, tôi đã làm. –

Trả lời

49

Có một dấu hiệu nổi tiếng cho not in. Về cơ bản, id not in (1,2,3) là viết tắt cho:

id <> 1 and id <> 2 and id <> 3 

Bây giờ nếu bảng TimeEntries của bạn có chứa bất kỳ hàng với một TaskID của null, các not in dịch để:

ID <> null and ID <> 1 and ID <> 2 AND ... 

Kết quả của một sự so sánh với null luôn là unknown . Vì unknown không đúng trong SQL, mệnh đề where lọc ra tất cả các hàng và bạn sẽ không xóa gì cả.

An dễ sửa chữa là thêm mệnh đề where trong subquery:

DELETE FROM Tasks 
WHERE ID not IN 
     (
     SELECT TaskID 
     FROM TimeEntries 
     WHERE TaskID is not null 
     ) 
+0

Bạn có gợi ý về cách làm việc này không? – DOK

+0

@DOK: Chắc chắn, một cách được thêm vào câu trả lời. SQLMenace đã đăng một câu trả lời hay khác – Andomar

+0

Câu trả lời hay. Cảm ơn rất nhiều! –

18

Một cách, điều này sẽ chăm sóc của 'vấn đề' bạn đang gặp với null (xem link bên dưới để biết thêm)

DELETE FROM Tasks 
WHERE NOT EXISTS (SELECT 1 FROM TimeEntries 
        WHERE TimeEntries.TaskID = Tasks.ID) 

Để hiểu được vấn đề bạn đang gặp phải, hãy nhìn vào Select all rows from one table that don't exist in another table

+0

Câu trả lời này tao nhã hơn tôi đoán. – wieczorek1990

3
Delete FROM Tasks 
     WHERE not Exists 
      (SELECT 'X' FROM TimeEntries where TimeEntries.TaskID = Tasks.ID) 

SQL ở trên sẽ xóa tất cả các hàng từ nhiệm vụ mà Task.ID không tồn tại trong bảng mục nhập thời gian. Tôi sẽ chạy nó như là một tuyên bố chọn đầu tiên để kiểm tra :)

9

Vì bạn đang chạy SQL 2008, bạn có thể sử dụng cú pháp hợp nhất mới tiện lợi.

MERGE Tasks AS target 
USING TimeEntries as Source ON (Target.TaskID=Source.TaskID) 
WHEN NOT MATCHED BY Source THEN DELETE; 
+1

+1: Một chút quá mức cần thiết trong trường hợp này, nhưng chắc chắn hữu ích khi biết về lệnh hợp nhất. Tôi thậm chí không biết một cái gì đó như thế này tồn tại. –

+1

Tại sao bạn cho rằng đó là quá mức cần thiết? Nó được tạo ra khá nhiều cho các nhiệm vụ như thế này (kết hợp các hàng giữa các bảng). – JohnFx

+1

Điều gì về hiệu suất của nó so với các giải pháp cũ? Liệu nó có bất kỳ lợi thế nào hay đây là cách được hỗ trợ để thực hiện các hành động như vậy? Thx –

3

Tôi biết điều này cũ, nhưng tôi tự hỏi tại sao không ai đề cập đến truy vấn xóa như được mô tả here. Vì vậy, để tham khảo:

DELETE FROM Tasks 
FROM Tasks LEFT OUTER JOIN 
    TimeEntries ON TimeEntries.TaskID = Tasks.ID 
WHERE TimeEntries.TaskID IS NULL; 

Cú pháp này không tương thích với ISO, vì vậy sẽ chỉ hoạt động cho T-SQL.

Các vấn đề liên quan