2014-07-03 37 views
1

在MySQL中,有可能在SELECT子句中有兩個CASE語句,其中第二個CASE語句依賴於第一個CASE語句?基於上一個CASE值的MySQL CASE

例如,考慮以下查詢:

SELECT CASE WHEN `user`.`id` < 500 THEN 'awesome' ELSE 'lame' END 
    AS `status` 

    , CASE WHEN `status` = 'awesome' THEN 'You rock' ELSE 'You stink' END 
    AS `message` 

    FROM `user` 

基本上,用戶ID判斷狀態,然後將狀態確定消息。

然而,正如你可能已經猜到了,這個查詢生成此錯誤:

Unknown column 'status' 

我到目前爲止發現的唯一的解決辦法是二生成一個臨時表,視圖,或者子查詢,然後message是由子查詢中返回的status決定。

有沒有辦法寫這個查詢,而不使用臨時表,視圖或子查詢?我試圖避免這些結構保持查詢簡單並儘可能優化。謝謝!

+1

我不認爲你可以做到這一點,至少有一個子查詢。我不認爲這會導致任何性能問題:) –

+1

@RodrigoAssis它可以做到(檢查下面的答案;)) – Barranka

+1

好!每天學習 –

回答

4

您可以使用臨時變量:

select 
    @status1 := (case 
     when user.id < 500 then 'awesome' 
     else 'lame' 
    end) as `status`, 
    (case 
     when @status1 = 'awesome' then 'You rock' 
     else 'You stink' 
    end) as message 
from 
    user; 

有些事情你必須瞭解的臨時變量:

  1. 他們總是通過@
    • 避免之前使用被保留文字,以防萬一(這就是我命名變量的原因
  2. @符號後,必須以字母開頭,並且一定不能有空格
  3. 當您在一個查詢更新,它們將被更新「左到右」(談欄目)和「倒數第一」(談論行)。這可以幫助您計算累計總和或平均值。

舉例(2點):

select @t := 1, @t := @t + 1; 

@t1 | @t2 
----+---- 
1 | 2 

舉例(3點):

select myTable.x, @t := @t + myTable.x as cummulative_x 
from 
    (select @t := 0) as init, -- You need to initialize the variable, 
           -- otherwise the results of the evaluation will be NULL 
    myTable 
order by myTable.x -- Always specify how to order the rows, 
        -- or the cummulative values will be quite odd 
        -- (and maybe not what you want) 
; 

x | cummulative_x 
---+--------------- 
1 | 1 
1 | 2 
2 | 4 
3 | 7 

臨時變量可以幫助你做一些真棒事...隨意玩耍;如果你想在這個查詢的結果定義條件)


更新

,有兩種方法可以做到這一點:

  1. 使用上述查詢作爲第二個查詢的數據源(即,使其成爲另一查詢的from子句中的子查詢
  2. 創建臨時表和查詢就可以了

選項1:

select a.* 
from (
    -- The query with temp variables defined 
) 
where -- ATTENTION: you need to write the references to the column names of the subquery 

選項2:(我個人最喜歡的)

drop table if exists temp_my_temp_table; 
create temporary table temp_my_temp_table 
    select 
     @status1 := (case 
      when user.id < 500 then 'awesome' 
      else 'lame' 
     end) as `status`, 
     (case 
      when @status1 = 'awesome' then 'You rock' 
      else 'You stink' 
     end) as message 
    from 
     user; 
-- Add all appropriate indexes to this newly created table: 
-- alter table temp_my_temp_table 
--  add index idx_status(`status`), 
--  add index idx_mess(message); 
-- Make your queries on this new temp table 
select * from temp_my_temp_table 
-- where ... 
; 

事情你必須瞭解一個臨時表:

  • 他們是在RAM中創建(默認情況下,只有當該表是不是太大)
  • 他們只是看到創建它
  • 他們被淘汰,一旦創建它關閉時,連接的連接(或終止以任何方式)
  • 您不能在FROM子句中多次使用它。除此之外,你可以在你的數據庫

另一個更新

只是偶然我碰到this question and its answer來使用它作爲任何其他表。如果你想用你列的結果作爲條件(含臨時變量計算),MySQL允許這樣的:

select 
    @status1 := (case 
     when user.id < 500 then 'awesome' 
     else 'lame' 
    end) as `status`, 
    (case 
     when @status1 = 'awesome' then 'You rock' 
     else 'You stink' 
    end) as message 
from 
    user 
having 
    `status` = 'awesome'; 

而不是使用where使用having,而不是指臨時變量,但到別名的列。

+0

感謝您的回答。它看起來像我不能在'WHERE'子句中使用臨時變量,這是正確的嗎?例如,如果我在查詢的末尾添加WHERE @ status1 ='awesome'',我會得到零結果。 –

+1

@Leo事實上,temp變量不能用在where子句中。然而,如果你需要這樣的解決方法......更新包含「技巧」 – Barranka

+0

好的,非常感謝你的更新。它看起來像是我想要使用多個'CASE'語句並對臨時變量進行過濾,畢竟我必須使用臨時表或子查詢。 –