2012-02-06 121 views
1

我遇到了一些MySQL選擇查詢的意外行爲。我正在查詢:意外的結果 - 基於日期比較的MySQL SELECT

SELECT `refno`, `subdomain`, `toplevels`, `renew_until`, `expiry_date`, 
(YEAR(`renew_until`) - YEAR(`expiry_date`)) AS `renew_for` FROM `testing_names` 
WHERE `expiry_date` >= DATE(NOW()) AND `renew_for` >= 0 

返回(如預期):

| refno | subdomain | toplevels | renew_until | expiry_date | renew_for | 
|-----------------------------------------------------------------------------------| 
| 5  | domain1 | com  | 2014-02-02 | 2014-02-02 | 0   | 
| 45  | domain2 | net  | 2014-01-27 | 2013-01-27 | 1   | 

但是下面的查詢(注意renew_for不同的比較)返回一個空集:

SELECT `refno`, `subdomain`, `toplevels`, `renew_until`, `expiry_date`, 
(YEAR(`renew_until`) - YEAR(`expiry_date`)) AS `renew_for` FROM `testing_names` 
WHERE `expiry_date` >= DATE(NOW()) AND `renew_for` > 0 

在這種情況下,我期待行#45;我的查詢出了什麼問題?我是否正確使用renew_for

回答

2

其他RDBMS將不允許使用此語法:列別名不應在WHERE子句中可用。
MySQL does it's own thing though結果不穩定:

標準SQL不允許您引用WHERE子句中的列別名。這種限制是因爲在執行WHERE代碼時,列值可能還沒有確定。

因此,WHERE條件改變這種

WHERE `expiry_date` >= DATE(NOW()) AND (YEAR(`renew_until`) - YEAR(`expiry_date`)) > 0 

或者使用派生表

SELECT * 
FROM 
    (
    SELECT 
     `refno`, `subdomain`, `toplevels`, `renew_until`, `expiry_date`, 
     (YEAR(`renew_until`) - YEAR(`expiry_date`)) AS `renew_for` 
    FROM `testing_names` 
    ) T 
WHERE `expiry_date` >= DATE(NOW()) AND `renew_for` > 0 
1

從採取進一步看,似乎使用HAVING將做在MySQL工作,用最簡單的語法;但據我瞭解,這是另一個MySQL做自己的事情(WHERE vs HAVING);所以如果要保持接近SQL標準的優先級,@ gbn的解決方案可能是最好的。

使用HAVING

SELECT `refno`, `subdomain`, `toplevels`, `renew_until`, `expiry_date`, 
(YEAR(`renew_until`) - YEAR(`expiry_date`)) AS `renew_for` FROM `testing_names` 
WHERE `expiry_date` >= DATE(NOW()) HAVING `renew_for` > 0