MySQL变量在case表达式中没有按预期工作

时间:2017-12-27 12:27:35

标签: mysql sql

以下是我的查询的一部分,其中变量@daysCASE表达式中不起作用,而它在以前版本的MariaDB中运行良好。如果我在案例的表达式部分中放置DATEDIFF('2018-02-26', '2018-02-22')来代替@days,但是如果我将它分配给变量,它为什么不起作用呢?

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`

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

您正在为变量赋值,并在同一语句中读取它们。不建议这样做。 From the manual

  

作为一般规则,除了在SET语句中,你永远不应该   为用户变量赋值并读取其中的值   言。

在查询之前放置SET语句

('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)

然后,您可以使用params.days和params.is_base替换所有@days和@is_base。

PS:我认为:

import csv
with open('test.csv', 'rb') as csvfile:
    spamreader = csv.reader(csvfile, delimiter=';', quotechar='|')
    lista = list(spamreader)
    print lista

可以写成:

>>>[['"Fecha"', '"Cliente"', '"Subastas"', '"Impresiones_exchange"', '"Fill_rate"', '"Importe_a_pagar_a_medio"', '"ECPM_medio"'],['20/12/2017', 'Martin', '165.665', '3.777', '2,28%', '1,58', '0,42'], ['21/12/2017', 'Martin', '229.620', '18.508', '8,06%', '14,56', '0,79'], ['22/12/2017', 'Martin', '204.042', '48.526', '23,78%', '43,98', '0,91'], ['20/12/2017', 'Tom', '102.613', '20.223', '19,71%', '17,86', '0,88'], ['21/12/2017', 'Tom', '90.962', '19.186', '21,09%', '14,26', '0,74'], ['22/12/2017', 'Tom', '60.189', '12.654', '21,02%', '11,58', '0,92']]