MySQL 值范围的 CASE 不起作用但嵌套的 IF 起作用?

MySQL CASE for value range doesn't work but nested IF's do?

我可能遗漏了一些非常非常简单的东西,但我终其一生都无法弄清楚我做错了什么...

我有这个查询,用于提取人们在志愿服务中完成的小时数,然后根据提交的小时数为他们分配奖励。不难...

嵌套的 IF 解决方案很糟糕,只是一个后备方案,看看它是否只是 CASE 搞砸了。事实证明,janky 嵌套 IF 解决方案完美运行,而我的 CASE 解决方案仍然存在问题。

该查询每年仅 运行 一次以得出最终结果,因此性能并不是真正的问题(嵌套 IF 查询当前的执行时间为 0.0095 秒/700 行,这已经足够了),更重要的是,它无法正常工作,这让我非常恼火,我想了解原因以供将来参考。

作为参考,小时值存储为 DECIMAL(8,2),随后 total_hours 的值也是相同类型。

我正在寻找的输出是:

| id | first_name | last_name  | total_hours | award    |
|----|------------|------------|-------------|----------|
| 1  | Bob        | Harrington | 0.50        | Silver   |
| 2  | Jim        | Halpert    | 800.00      | Platinum |
| 3  | Dwight     | Shrute     | 130.00      | Gold     |
| 4  | Michael    | Scott      | 5.00        | Bronze   |

CASE 语句导致 award 的所有行都具有 'Less than 1 hour' 的值,除了那些 total_hours 等于 1.00 的行,其中 award 的值等于'Bronze'.

嵌套的 IF 语句导致 table 正确生成,如上例所示。

这是我当前的 CASE 查询,它不起作用:

SELECT
    m.id,
    m.first_name,
    m.last_name,
    total_hours,
    CASE total_hours
        WHEN total_hours >= 1 <= 50 THEN
            'Bronze'
        WHEN total_hours >= 51 <= 125 THEN
            'Silver'
        WHEN total_hours >= 126 <= 249 THEN
            'Gold'
        WHEN total_hours >= 250 THEN
            'Platinum'
        ELSE
            'Less than 1 hour'
    END AS award
FROM (
    SELECT member_id, sum(hours) total_hours
    FROM volunteering_hours
    WHERE authorise_date > 0 AND validate_date > 0 AND delete_date = 0
    GROUP BY member_id
) hour_query
LEFT JOIN members m ON m.id = member_id
ORDER BY total_hours DESC

到目前为止我尝试过的:

我当前的嵌套 IF 解决方案看起来很糟糕,但至少可以正常工作,是:

SELECT
    m.id,
    m.first_name,
    m.last_name,
    total_hours,
    IF(total_hours >= 1 && total_hours <= 50, 'Bronze',
        IF(total_hours >= 51 && total_hours <= 125, 'Silver',
            IF(total_hours >= 126 && total_hours <= 249, 'Gold',
                IF(total_hours >= 250, 'Platinum', 'Less than 1 hour')
            )
        )
    ) award
FROM (
    SELECT member_id, sum(hours) total_hours
    FROM volunteering_hours
    WHERE authorise_date > 0 AND validate_date > 0 AND delete_date = 0
    GROUP BY member_id
) hour_query
LEFT JOIN members m ON m.id = member_id
ORDER BY total_hours DESC

有人可以告诉我一些关于 CASE 为何不起作用的知识吗?

提前致谢。 :)

尝试以下方法。

SELECT
    m.id,
    m.first_name,
    m.last_name,
    total_hours,
    CASE WHEN total_hours between 1 and 50 THEN
            'Bronze'
        WHEN total_hours between 51 and 125 THEN
            'Silver'
        WHEN total_hours between 126 and 249 THEN
            'Gold'
        WHEN total_hours between 250 THEN
            'Platinum'
        ELSE
            'Less than 1 hour'
    END AS award
FROM (
    SELECT member_id, sum(hours) total_hours
    FROM volunteering_hours
    WHERE authorise_date > 0 AND validate_date > 0 AND delete_date = 0
    GROUP BY member_id
) hour_query
LEFT JOIN members m ON m.id = member_id
ORDER BY total_hours DESC

我不确定你是否可以在你的 cases 语句中使用 between ,但我认为你可以。如果你不能,那么你只需要在你的案例声明中像 total_hours >=1 and total_hours <=50 一样正确地分解它。

对于您的查询,我建议您将其重组为

select
    m.id,
    m.first_name,
    m.last_name,
    sum(vh.hours) total_hours,
    case when sum(vh.hours) between 1 and 50 then
            'bronze'
        when sum(vh.hours) between 51 and 125 then
            'silver'
        when sum(vh.hours) between 126 and 249 then
            'gold'
        when sum(vh.hours) between 250 then
            'platinum'
        else
            'less than 1 hour'
    end as award
from
    volunteering_hours vh

    left join members m on 
        m.id = member_id
where 
    authorise_date > 0 and 
    validate_date > 0 and 
    delete_date = 0
group by 
    vh.member_id,
    m.id,
    m.first_name,
    m.last_name
order by 
    total_hours desc

嵌套表不是很好,您应该尽可能避免使用它们。更干净一点,我认为分组仍然可以正常工作。

你很接近,但有一些语法错误。改为这样做:

CASE 
    WHEN total_hours >= 1 AND total_hours <= 50 THEN
        'Bronze'
    WHEN total_hours >= 51 AND total_hours <= 125 THEN
        'Silver'
    WHEN total_hours >= 126 AND total_hours <= 249 THEN
        'Gold'
    WHEN total_hours >= 250 THEN
        'Platinum'
    ELSE
        'Less than 1 hour'
END AS award

Sample simplified SQL Fiddle

您混合了(不同的)大小写语法。

如果您正在使用 case xx,那么您的 WHEN 不应再次包含 xx

case xx
  when 1 then statement
  when 2 then statement

如果您只使用 case,那么您可能需要提供要比较的变量:

case
  when xx=1 then statement
  when xx=2 then statement

参见此处示例: http://sqlfiddle.com/#!9/d8348/6

与编程语言相比,第一种等于

switch(variable){
   case 1: statement; break;
   case 2: statement; break;
}

而第二个是

if (variable==1){
   statement;
else if (variable==2){
   statement;
}