Làm cách nào để kiểm tra xem một truy vấn con có chính xác một kết quả khác biệt và một giá trị được chỉ định chính xác không?


10

Tôi thấy mình viết như sau:

select 'yes' 
where exists(select * from foo where val=1)
and not exists(select * from foo where val<>1);

và tự hỏi nếu có một cách ngắn gọn hơn mà không phải hy sinh quá nhiều khả năng đọc.

Tôi đã tìm thấy một cách mà tôi đang đăng như một câu trả lời nhưng tôi không hoàn toàn hài lòng với nó và sẽ rất quan tâm đến các lựa chọn thay thế

Trong trường hợp valnày là duy nhất trong foo- không có bản sao


Tôi có hiểu chính xác rằng bạn muốn chính xác một hàng trong kết quả của truy vấn con không?
Erwin Brandstetter


Một trong những bạn đề cập trong tiêu đề. Tôi không chắc liệu nó sẽ là một kết quả sau hay trước "khác biệt".
Erwin Brandstetter

À đúng rồi, cái đó :) Tôi khá bối rối khi đề cập đến truy vấn phụ trong câu trả lời của tôi - câu hỏi của bạn cụ thể và linh hoạt hơn nhiều, ví dụ bạn cũng có thể sử dụng count(distinct val), mặc dù trong trường hợp thực tế của tôi, nó không có gì khác biệt
Jack nói thử topanswers.xyz

Câu trả lời:


8

Súc tích, nhanh chóng (đặc biệt là có nhiều hàng), yêu thích của tôi liên quan đến khả năng đọc và cũng sẽ hoạt động với bản sao:

SELECT count(*) = 1 AND min(val) = 1 FROM foo;

Trả về TRUE/ FALSE.. hoặc NULL- chỉ trong trường hợp chính xác một hàng với val IS NULL, bởi vì count()không bao giờ trả lại NULLhoặc không có hàng.

Thứ hai 1trong ví dụ chỉ xảy ra giống như lần đầu tiên, vì ví dụ của bạn.


Các truy vấn trong câu hỏi không thành công với NULLcác giá trị. Hãy xem xét bản demo đơn giản:

CREATE TABLE foo (id int, val int);
INSERT INTO foo VALUES (1, 1),(2, NULL);

SELECT 'yes' 
WHERE      EXISTS(SELECT * FROM foo WHERE val =  1)
AND    NOT EXISTS(SELECT * FROM foo WHERE val <> 1);

IS DISTINCT FROMsẽ khắc phục điều này, nhưng nó vẫn có thể thất bại với các bản sao trong val- mà bạn đã loại trừ trong trường hợp này.


Câu trả lời của bạn hoạt động tốt.
Trả về 'yes'/ không có hàng.

Tôi thích hình thức ngắn hơn này, mặc dù. Đừng quên rằng PostgreSQL (không giống như Oracle) có một booleanloại thích hợp .

SELECT array_agg(val) = array[1] FROM foo;

Trả về TRUE/ FALSE/ NULL.


tuyệt vời, cảm ơn, tôi biết sẽ có cách tốt hơn :)
Jack nói hãy thử topanswers.xyz

5

Một biến thể về câu trả lời của @ Erwin. Không COUNT(), chỉ có MIN()MAX(). Nó có thể hiệu quả hơn một chút với bảng lớn và (không phải trong trường hợp của bạn) trùng lặp val:

SELECT MIN(val) = 1 AND MAX(val) = 1 FROM foo;

+1 cảm ơn. Nó xử lý null và trùng lặp khác nhau tất nhiên (nếu có)
Jack nói hãy thử topanswers.xyz

@Jack: Vâng. Bảng của bạn có null không? Hoặc bạn muốn câu trả lời cho cả hai trường hợp (có và không có)?
ypercubeᵀᴹ

không có của tôi không - Tôi cũng có thể sử dụng :)
Jack nói hãy thử topanswers.xyz

Sẽ nhanh hơn nhiều trên các bảng lớn hơn với chỉ mục phù hợp, nhưng thực hiện giống hệt nhau khi không có chỉ mục đó - như khi kiểm tra kết quả truy vấn.
Erwin Brandstetter


1

Điều này trả về true, falsehoặc một kết quả trống:

 select j.val is null 
 from foo left join foo as j on j.val <> foo.val 
 where foo.val = 1 limit 1;

Thoạt nhìn, điều này dường như không trở lại falsenếu có giá trị ở foođâu val<>1?
Jack nói hãy thử topanswers.xyz

@JackDoumund ơi, xin lỗi. Tôi hiểu nhiệm vụ sai lần đầu tiên. Đã sửa.
Grayhemp

Hoạt động - ngoại trừ với NULLgiá trị chưa được loại trừ trong trường hợp này.
Erwin Brandstetter

@ErwinBrandstetter NULLcó thể được giải quyết bằng cách sử dụng IS [NOT] DISTINCT FROMtôi nghĩ.
Grayhemp

1
@grayhemp: Không phải trong trường hợp này. LEFT JOIN foo j ON j.val <> foo.valkhông phát hiện ra một hàng với j.val IS NULLbắt đầu bằng. Nếu bạn bao gồm nó với ON j.val IS DISTINCT FROM foo.valbạn thì bạn cần kiểm tra một cột khác jđược xác định NOT NULLđể phân biệt hai trường hợp. Nhưng không có cột bổ sung được xác định.
Erwin Brandstetter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.