2013-04-24 51 views
5

Cách tốt nhất để thực hiện điều này trong một truy vấn trong mysql là gì?Một mệnh đề WHERE khác nếu không có kết quả

SELECT * FROM products WHERE language = 1 

nếu không có kết quả

SELECT * FROM products WHERE language = 2 AND country = 1 

nếu không có kết quả

SELECT * FROM products WHERE language = 2 AND country = 2 
+0

Cột nào là '*'? – Kermit

+0

Đây không phải là một truy vấn trong MySQL không may: bạn mong đợi gì để thoát khỏi nó – gbn

+0

Tôi nghĩ bạn có thể nhận được kết quả "hợp lý" mong muốn với ORDER – lvil

Trả lời

7

Tôi đã chỉnh sửa nó để làm cho nó hoạt động, nhưng nó không còn thanh lịch nữa.


Bản gốc (không có lần cuối cùng và không tồn tại) có lỗi.

Hóa ra điều này không thông minh như tôi nghĩ. Xem bình luận dưới đây. Nó không thành công nếu các truy vấn thứ nhất và thứ ba trả về dữ liệu. Nó hoạt động nếu bạn chỉ có một công đoàn, nhưng không có hai hoặc nhiều hơn.


Đó là khá dễ dàng trong mysql:

select SQL_CALC_FOUND_ROWS * from products where language = 1 
union 
SELECT * FROM products WHERE language = 2 AND country = 1 and found_rows()=0 
union 
SELECT * FROM products WHERE language = 2 AND country = 2 and found_rows()=0 
AND not exists(select * from products where language = 1) 

Xem các cuộc thảo luận của found_rows() và SQL_CALC_FOUND_ROWS đây: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows

+1

Bạn có thể dựa vào found_rows trong tuyên bố UNION không? – gbn

+0

+1 cho ý tưởng! :) – biziclop

+0

@gbn Bạn có thể nếu bạn không sử dụng LIMIT ở bất kỳ đâu và kiểm tra 0. –

1

MySQL thiếu tính năng để cho phép này trong một đi
Ví dụ: DENSE_RANK chức năng cửa sổ, hoặc TOP..WITH TIES

Vì vậy, mà không cần sử dụng một bảng tạm thời hoặc các câu lệnh IF (yêu cầu một thủ tục lưu sẵn trong MySQL anyway), sau đó lọc nó trên máy khách với giá trị ưu tiên thấp nhất. Tức là, hãy tiêu thụ hàng cho đến khi giá trị thay đổi

SELECT *, 1 AS priority FROM products WHERE language = 1 
UNION ALL 
SELECT *, 2 AS priority FROM products WHERE language = 2 AND country = 1 
UNION ALL 
SELECT *, 3 AS priority FROM products WHERE language = 2 AND country = 2 
ORDER BY priority; 

Điều này sẽ loại bỏ khứ hồi tới máy chủ MySQL, ngay cả khi không lý tưởng. Và nó cũng tránh đánh giá lại các CHỌN trước đó trong các mệnh đề EXISTS

+0

Bạn có thể thực hiện việc này trong một lựa chọn duy nhất nếu bạn đã đánh giá mức ưu tiên là điều kiện trường hợp - ví dụ như 'trường hợp ngôn ngữ khi 1 thì 1 khi 2 thì ngôn ngữ + quốc gia khác 4 kết thúc'. –

2

Bạn có thể sử dụng giống như sau: (chỉnh sửa để sử dụng EXISTS và LIMIT dựa trên nhận xét).

(
SELECT * FROM products WHERE language = 1 
) 
UNION 
(
SELECT * FROM products WHERE language = 2 AND country = 1 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 1 limit 1) 
) 
UNION 
(
SELECT * FROM products WHERE language = 2 AND country = 2 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 2 AND country = 1 limit 1) 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 1 limit 1) 
) 

Bạn kiểm tra các truy vấn lồng nhau và đếm (*) truy vấn trước đó là NULL.

+2

Việc sử dụng không tồn tại có thể tốt hơn việc kiểm tra số 0. –

+0

@ShawnBalestracci các truy vấn phụ đó (COUNT hoặc EXISTS - không quan trọng) có được thực hiện lại trên mỗi hàng không? Có lẽ còn lại tham gia + kiểm tra null sẽ là cách tiếp cận tốt hơn? –

+0

Tôi có cảm giác mạnh mẽ rằng trình tối ưu hóa tính toán nhánh tối ưu và tính toán trước chỉ một lần. Đó là lý do tại sao các công cụ SQL làm :). –

1

Hãy thử:

select p.* 
from (select min(language) minlang, min(country) minctry 
     from products where language = 1 or 
          (language = 2 and country in (1,2))) c 
join products p 
on p.language = c.minlang and (c.minlang=1 or p.country=c.minctry) 
1

Có vẻ như không có cách nào tốt và nếu có thể, bạn nên làm cho nó thành một thủ tục, hoặc điền vào bảng tạm thời hoặc trả lại đối tượng RowSet cho khách hàng

thế nào bao giờ nếu không có gì có thể bạn dường như đã giới hạn các truy vấn thứ cấp và đại học:

SELECT * FROM products WHERE language = 1 

UNION ALL 

SELECT * FROM products WHERE language = 2 AND country = 1 
    AND NOT EXISTS (SELECT * FROM products WHERE language = 1) 

UNION ALL 

SELECT * FROM products WHERE language = 2 AND country = 2 
    AND NOT EXISTS (SELECT * FROM products WHERE language = 1 OR (language = 2 AND country = 1)) 

Nhưng điều đó phải xấu và chậm.

Có thể LEFT JOIN với IS NULL sẽ tốt hơn NOT EXISTS mặc dù

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