2016-11-07 26 views
1

這有點奇怪:我有以下的MySQL存儲過程(或函數),大多數可以安全地忽略,除非需要了解完整的圖片。問題是ORDER BY子句。現在ORDER BY子句的MySQL IF語句問題

BEGIN 

    SELECT DISTINCT e.*, (3959 * acos(cos(radians(in_latitude)) * cos(radians(e.address_latitude)) 
     * cos(radians(e.address_longitude) - radians(in_longitude)) + sin(radians(in_latitude)) 
     * sin(radians(e.address_latitude)))) AS distanceFromUsersPostcode 
    FROM event e 
    INNER JOIN event_organiser eo on e.event_organiser_id = eo.id 
    WHERE (e.event_name LIKE in_search OR e.address_town LIKE in_search OR e.address_county LIKE in_search OR eo.event_organiser_name LIKE in_search) 
    AND e.start_date_time >= in_start_date 
    AND e.start_date_time <= in_end_date 
    AND e.enabled = true 
    HAVING distanceFromUsersPostcode < in_maxDistanceFromUser 
    /* 
     * 1 * 
     ORDER BY distanceFromUsersPostcode 
     * 2 * 
     ORDER BY IF(in_orderBy='LOCATION', CAST(distanceFromUsersPostcode AS DECIMAL), e.start_date_time) ASC; 
    */ 
    ORDER BY 
     CASE in_orderBy 
      WHEN 'LOCATION' THEN distanceFromUsersPostcode 
      ELSE e.start_date_time 
     END 
    ASC; 

END 

的問題是這樣的,目前註釋掉ORDER BY子句好像對待十進制值distanceFromUsersPostcode爲VARCHAR(或字符串)值。

它訂單的結果形式:

0.4,101.9,102.8,11.1,11.9

同樣可以如果我用標記爲* 2 *

所述變體然而說,如果我恢復到標記爲* 1 *原來的變種,其結果將被責令按預期:

0.4,11.1,11.9,101.9,102.8

我的猜測如果在IF函數(* 2 *)內部使用了,則MySQL將distanceFromUsersPostcode變量視爲VARCHAR,因此我試圖將其轉換爲DECIMAL。但是,這不起作用。

任何人都可以揭示這裏發生的事情嗎?

下列行爲如預期,但也不是很優雅,當然,因爲它複製了整個查詢:

BEGIN 
    IF in_orderBy='LOCATION' THEN 

     SELECT DISTINCT e.*, (3959 * acos(cos(radians(in_latitude)) * cos(radians(e.address_latitude)) 
      * cos(radians(e.address_longitude) - radians(in_longitude)) + sin(radians(in_latitude)) 
      * sin(radians(e.address_latitude)))) AS distanceFromUsersPostcode 
     FROM event e 
     INNER JOIN event_organiser eo on e.event_organiser_id = eo.id 
     WHERE (e.event_name LIKE in_search OR e.address_town LIKE in_search OR e.address_county LIKE in_search OR eo.event_organiser_name LIKE in_search) 
     AND e.start_date_time >= in_start_date 
     AND e.start_date_time <= in_end_date 
     AND e.enabled = true 
     HAVING distanceFromUsersPostcode < in_maxDistanceFromUser 
     ORDER BY distanceFromUsersPostcode; 

    ELSE 

     SELECT DISTINCT e.*, (3959 * acos(cos(radians(in_latitude)) * cos(radians(e.address_latitude)) 
      * cos(radians(e.address_longitude) - radians(in_longitude)) + sin(radians(in_latitude)) 
      * sin(radians(e.address_latitude)))) AS distanceFromUsersPostcode 
     FROM event e 
     INNER JOIN event_organiser eo on e.event_organiser_id = eo.id 
     WHERE (e.event_name LIKE in_search OR e.address_town LIKE in_search OR e.address_county LIKE in_search OR eo.event_organiser_name LIKE in_search) 
     AND e.start_date_time >= in_start_date 
     AND e.start_date_time <= in_end_date 
     AND e.enabled = true 
     HAVING distanceFromUsersPostcode < in_maxDistanceFromUser 
     ORDER BY e.start_date_time; 

    END IF; 
END 

回答

0

因爲你使用MySQL的排序不同的數據類型會嘗試將它們轉換爲東西方便是能夠比較這些值。在你的具體情況下,它將轉換爲字符串。所以將distanceFromUsersPostcode轉換爲數字是沒有意義的,因爲它會被轉換回字符串。您將需要以便於格式進行數字排序的字符串轉換。 LPAD函數將幫助你在這裏。

ORDER BY 
    CASE in_orderBy 
     WHEN 'LOCATION' THEN LPAD(CAST(distanceFromUsersPostcode as CHAR),6) 
     ELSE e.start_date_time 
    END 
ASC; 
+0

感謝您的評論。它沒有按照你的建議進行編譯,而是將它改爲LPAD(CAST(distanceFromUsersPostcode as CHAR),6,'0')用零填充到左邊的pad。然而,不幸的是,它沒有像預期的那樣工作,就像以前一樣。 –

+0

但是,這讓我想到了MySQL正在應用詞法排序(所以這兩種類型匹配)的事實。我設法通過使用WHEN'LOCATION'THEN(distanceFromUsersPostcode + 10000)來使查詢工作。這已經解決了這個問題,但讓我更加關注。 MySQL現在正在執行詞法排序,而不是按數字(或日期)進行排序,具體取決於提供的排序。我在別處讀過這可能會導致查詢運行速度慢得多。如果是這種情況,我會更快樂地複製原來顯示的代碼段。不太優雅但更快速的查詢。有什麼想法嗎? –

+0

我很高興你能工作。這種排序要求並不常見。你能不能以不同的方式思考你的要求? –