2011-09-11 20 views
6

Các truy vấn sau đây trả về 2036 hàng:Tôi điên: PostgreSQL TRÊN điều hành với truy vấn lồng nhau trở về kết quả bất ngờ

SELECT "FooUID" from "Foo" f 
LEFT JOIN "Bar" b ON f."BarUID" = b."BarUID" 
WHERE f."BarUID" IS NOT NULL AND b."BarUID" IS NULL 

Nhưng tuyên bố sau chỉ cập nhật 1870 hàng:

UPDATE "Foo" f1 set "BarUID" = 'aNewUID' 
WHERE f1."FooUID" IN (
    SELECT f2."FooUID" from "Foo" f2 
    LEFT JOIN "Bar" b ON f2."BarUID" = b."BarUID" 
    WHERE f2."BarUID" IS NOT NULL AND b."BarUID" IS NULL 
) 

Làm thế nào có thể như vậy ?

CHỈNH SỬA 1: Truy vấn đầu tiên tiếp tục trả về 166 hàng và truy vấn thứ hai tiếp tục cập nhật 0 hàng.

EDIT 2:

Trong phần tiếp theo, truy vấn lồng nhau trả về một hàng chứa một UID, nhưng truy vấn bên ngoài trả về 0 hàng.

SELECT * from "Foo" f1 
WHERE f1."FooUID" = (
    SELECT f2."FooUID" FROM "Foo" f2 
    LEFT JOIN "Bar" b ON f2."BarUID" = b."BarUID" 
    WHERE f2."BarUID" IS NOT NULL AND b."BarUID" IS NULL 
    LIMIT 1 
) 

Tôi có bị điên không?

EDIT 3:

Các phát biểu sau đây, được cung cấp bởi @wildplasser thành công trong việc cập nhật 166 hàng còn lại:

UPDATE "Foo" ff 
SET "BarUID" = 'aNewUID' 
WHERE ff."BarUID" IS NOT NULL 
AND NOT EXISTS (
    SELECT * FROM "Bar" bb 
    WHERE bb."BarUID"= ff."BarUID" 
) 

Tuy nhiên, tôi vẫn không hiểu tại sao ban đầu không chọn chúng lên. Nếu truy vấn lồng nhau được chọn 166 "FooUID" s, tại sao chúng không được đối sánh với các hàng trong bảng "Foo" bằng cách sử dụng IN?

EDIT 4: Tôi càng nghĩ về nó, nền tảng này có thể là quan trọng:

này tất cả đã diễn ra trên máy chủ cơ sở dữ liệu gần đây đã được nhân bản từ một số khác. Tôi đã nói chuyện với anh chàng CNTT đã làm nhân bản, và hóa ra anh ta đã không tắt một ứng dụng chạy trên đầu DB gốc trước khi đưa nó xuống để sao chép nó. Điều này có nghĩa là DB hầu như có khả năng đưa ra giữa giao dịch (tôi không biết làm thế nào vô ơn). Có thể một cái gì đó trong cơ sở dữ liệu đã bị bỏ lại ở trạng thái bị hỏng, dẫn tôi đến xem những hàng ảo này không?

Thật không may là tôi không còn có thể repro nó nữa, kể từ khi chạy sửa chữa của wildplasser. DB ban đầu (lên và phục vụ lại ứng dụng) không có dữ liệu không hợp lệ nào mà tôi đang cố gắng khắc phục trên bản sao, ít hơn bất kỳ dấu vết nào của các shenanigans mà tôi đã chứng kiến.

Tôi nên đề cập rằng trước khi chạy bản sửa lỗi, tôi đã giảm vấn đề về tính cơ bản nhất: Lần đầu tiên tôi chọn FooUID từ truy vấn lồng nhau trong Chỉnh sửa 2, sao chép nó vào khay nhớ tạm, sau đó chạy truy vấn chọn từ FooFooUID bằng giá trị được dán - điều này vẫn còn trả về 0 hàng.

+0

Loại nào là 'FooUID' và loại nào được trả về bởi truy vấn bên trong trong EDIT 2? Không có ý tưởng gì đang xảy ra, chỉ cần poking xung quanh một chút. –

+0

@mu quá ngắn - 'FooUID' là loại' uuid'. Bạn không chắc chắn tôi hiểu phần thứ hai của câu hỏi của bạn. –

+0

EDIT 2 của bạn đã khiến tôi bối rối. Phải là một giá trị không so sánh với chính nó. Bạn đang _sure_ phần bên trong đang trả về một NULL 'FooUID' không? –

Trả lời

2

gì sẽ xảy ra nếu bạn viết lại điều này với không tồn tại, như

UPDATE Foo ff 
SET baruid = 'aNewUID' 
WHERE ff.baruid IS NOT NULL 
AND NOT EXISTS (SELECT * FROM bar bb 
    WHERE bb.baruid = ff.baruid 
    ); 

Trông sạch hơn nhiều với tôi hơn chọn chân chân tay của một bên ngoài tham gia.

+0

Ngoài ra, một ràng buộc khoá ngoại có lẽ sẽ tránh được mớ hỗn độn này. – wildplasser

+0

Hài hước bạn nên đề cập đến, đây là tôi đang cố gắng để làm sạch dữ liệu xấu để thêm các phím nước ngoài. –

+0

Gheghe. Thử thêm tên tương quan vào truy vấn phụ. Có lẽ ai đó đã nhầm lẫn khi nhìn thấy hai con thú. Bạn cũng có thể kiểm tra các kế hoạch wuery (tên tương quan có ích trong đó, quá) – wildplasser

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