2017-12-27 151 views
1

以下是我的查詢的一部分,其中變量@daysCASE表達式中不起作用,但它在以前版本的MariaDB中運行良好。如果我把DATEDIFF('2018-02-26', '2018-02-22')代替案例的表達部分中的@days,但如果我將它分配給一個變量,它爲什麼不工作?MySQL變量無法按預期方式處理大小寫表達式

SELECT @is_base := 'Yes', @days := DATEDIFF('2018-02-26', '2018-02-22') days, 
(CASE 
    WHEN (@is_base = 'No' AND @days < 7) THEN r.nightly * @days 
    WHEN (@is_base = 'No' AND @days >= 7 AND @days < 28) THEN (r.weekly/7) * @days 
    WHEN (@is_base = 'No' AND @days >= 28) THEN (r.monthly/28) * @days 
    ELSE u.base_rate_nightly * @days 
END) AS total_price 

更新下面是完整的查詢。

`SELECT `u`.`ID`, `u`.`destination`, `u`.`unit_name`, `u`.`base_rate_nightly`, `u`.`lat`, `u`.`lng`, `u`.`number_of_bedrooms`, `u`.`max_guests`, `r`.`ID` as `rate_id`, `r`.`nightly`, `r`.`weekly`, `r`.`monthly`, `i`.`filename`, `t`.`name` as `unit_type`, @days := DATEDIFF('2018-02-26', '2018-02-22') days, `u`.`base_rate_nightly` as `total_price`, 'Yes' is_base, @is_base := if(('2018-02-22' <= r.enddate) and ('2018-02-26' >= r.startdate) or ('2018-02-22' <= r.enddate) and (r.startdate <= '2018-02-26'), 'No', 'Yes') as is_base, CASE 
         WHEN (@is_base = 'No' AND @days < 7) THEN r.nightly * @days 
         WHEN (@is_base = 'No' AND @days >= 7 AND @days < 28) THEN (r.weekly/7) * @days 
         WHEN (@is_base = 'No' AND @days >= 28) THEN (r.monthly/28) * @days 
         ELSE u.base_rate_nightly * @days 
        END AS total_price 
FROM `vs_units` `u` 
LEFT JOIN `vs_unit_images` `i` ON `u`.`ID` = `i`.`ID_unit` 
LEFT JOIN `vs_unit_rates` `r` ON `u`.`ID` = `r`.`ID_unit` AND (('2018-02-22' <= r.enddate) and ('2018-02-26' >= r.startdate) or ('2018-02-22' <= r.enddate) and (`r`.`startdate` <= '2018-02-26')) 
LEFT JOIN `vs_unit_types_readonly` `t` ON `t`.`ID` = `u`.`ID_unit_type` 
WHERE `u`.`max_guests` >= '1' 
AND (
`u`.`ID` NOT IN(SELECT DISTINCT ID_unit from vs_calendar WHERE ('2018-02-22' <= enddate) and ('2018-02-26' >= `startdate`) or ('2018-02-22' <= `enddate`) and (startdate <= '2018-02-26')) 
) 
GROUP BY `u`.`ID` 

回答

1

問題不在於CASE表達式。它是在多列中使用變量。 MySQL不保證表達式中變量賦值的順序。

就你而言,你有一個簡單的解決方案。只要將邏輯到FROM子句:

SELECT @days as days, 
     (CASE WHEN @is_base = 'No' AND @days < 7 THEN r.nightly * @days 
      WHEN @is_base = 'No' AND @days >= 7 AND @days < 28 THEN (r.weekly/7) * @days 
      WHEN @is_base = 'No' AND @days >= 28 THEN (r.monthly/28) * @days 
      ELSE u.base_rate_nightly * @days 
     END) AS total_price 
FROM (SELECT @is_base := 'Yes', 
      @days := DATEDIFF('2018-02-26', '2018-02-22') 
    ) params; 

FROM子句是保證SELECT之前進行評估。

我要指出的是這種結構,就沒有必要使用變量:

SELECT days, 
     (CASE WHEN is_base = 'No' AND days < 7 THEN r.nightly * days 
      WHEN is_base = 'No' AND days >= 7 AND days < 28 THEN (r.weekly/7) * days 
      WHEN is_base = 'No' AND days >= 28 THEN (r.monthly/28) * days 
      ELSE u.base_rate_nightly * days 
     END) AS total_price 
FROM (SELECT 'Yes' as is_base, 
      DATEDIFF('2018-02-26', '2018-02-22') as days 
    ) params; 
+0

感謝您的修正,讓我試試吧。 :-) – Muhammad

1

要分配給變量,並閱讀他們相同的語句裏面。這不被推薦。 From the manual

作爲一般規則,比SET語句等,你永遠不應該 值分配給一個用戶變量和相同的 語句中讀出的值。

放置SET聲明之前,請查詢:

SET @is_base := 'Yes'; 
SET @days := DATEDIFF('2018-02-26', '2018-02-22'); 

SELECT 
    @is_base, 
    @days AS days, 
    CASE 
     WHEN (@is_base = 'No' AND @days < 7) THEN r.nightly * @days 
     WHEN (@is_base = 'No' AND @days >= 7 AND @days < 28) THEN (r.weekly/7) * @days 
     WHEN (@is_base = 'No' AND @days >= 28) THEN (r.monthly/28) * @days 
     ELSE u.base_rate_nightly * @days 
    END AS total_price 
FROM r 

至於修改後的查詢,我想你可以簡單地將派生表中的所有變量,並加入剩餘的表吧:

FROM `vs_units` `u` 
INNER JOIN (
    SELECT 
     CASE 
      WHEN ('2018-02-22' <= r.enddate) and ('2018-02-26' >= r.startdate) or ('2018-02-22' <= r.enddate) and (r.startdate <= '2018-02-26') THEN 'No' 
      ELSE 'Yes' 
     END as is_base, 
     DATEDIFF('2018-02-26', '2018-02-22') AS days 
) params 
LEFT JOIN `vs_unit_images` `i` ON `u`.`ID` = `i`.`ID_unit` 
LEFT JOIN `vs_unit_rates` `r` ON `u`.`ID` = `r`.`ID_unit` AND (('2018-02-22' <= r.enddate) and ('2018-02-26' >= r.startdate) or ('2018-02-22' <= r.enddate) and (`r`.`startdate` <= '2018-02-26')) 
LEFT JOIN `vs_unit_types_readonly` `t` ON `t`.`ID` = `u`.`ID_unit_type` 

然後,您可以用params.days和params.is_base替換所有@days和@is_base。

PS:我覺得這個:

('2018-02-22' <= enddate) and ('2018-02-26' >= startdate) or ('2018-02-22' <= enddate) and (startdate <= '2018-02-26') 

可以寫成:

('2018-02-22' <= enddate) and ('2018-02-26' >= startdate) 
+0

感謝您的回答:-),根據@戈登「MySQL不保證表達式中變量的賦值順序」,所以我認爲它不會工作,另一個問題是我使用Codeigniter的查詢生成器使用set的東西有點棘手,我已經嘗試過了,但是我失敗了。 – Muhammad

+0

@穆罕默德看到其他答案,第二個選項。這正是我平時所做的。 –

+0

我正在嘗試,但沒有運氣,查詢是相當複雜的,讓我發佈整個查詢,在問題中。 – Muhammad

相關問題