2017-04-24 150 views
0

我認爲一旦CASE找到匹配項,就會中斷並返回第一個匹配項。但是,我得到所有匹配的案件陳述。例如Oracle多個CASE語句評估爲true

select distinct PERSON, 
       LOCATION, 
       (case 
        when LOCATION = 'CA' and PHONE is not null 
        then PHONE 
        when LOCATION = 'NY' and PHONE is not null 
        then PHONE 
        when LOCATION = 'FL' and PHONE is not null 
        then PHONE 
        when LOCATION = 'MA' and PHONE is not null 
        then PHONE 
        else '---' 
       end) 
from DIRECTORY 
where LOCATION in 
    ('CA', 'NY', 'FL', 'MA'); 

因爲人可以在每個國家的電話號碼,我要的是發現,基本上是「排名」由各州的順序第一電話號碼。我得到的是所有找到的電話號碼。

THX ...

回答

2

你可以指定一個排名在子查詢每個狀態,然後保留每個人的最高排名紀錄:

WITH cte1 AS (
    SELECT 
     PERSON, 
     LOCATION, 
     PHONE, 
     CASE WHEN LOCATION = 'CA' AND PHONE IS NOT NULL THEN 1 
      WHEN LOCATION = 'NY' AND PHONE IS NOT NULL THEN 2 
      WHEN LOCATION = 'FL' AND PHONE IS NOT NULL THEN 3 
      WHEN LOCATION = 'MA' AND PHONE IS NOT NULL THEN 4 
      ELSE 5  -- the NULL case 
     END AS LOCATION_RANK 
    FROM DIRECTORY 
    WHERE LOCATION IN ('CA', 'NY', 'FL', 'MA') 
), 
cte2 AS (
    SELECT t.*, 
      ROW_NUMBER() OVER (PARTITION BY t.PERSON ORDER BY t.LOCATION_RANK) rn 
    FROM cte1 t 
) 
SELECT 
    t.PERSON, 
    t.LOCATION, 
    COALESCE(t.PHONE, '---') 
FROM cte2 t 
WHERE t.rn = 1 
+0

謝謝 - 這是我失蹤的第二個cte。試圖從第一個cte中拉出像max(LOCATION_RANK)這樣的東西,但仍然返回了所有行。這太好了 - 非常感謝... – user1628169

0

@ TimBielgeleisen的CTE方法可能更容易遵循並維持,但你可以做同樣的事情,沒有任何熱膨脹係數,用keep dense_rank,雖然你有重複的情況下表達:

select person, 
    min(location) keep (dense_rank first order by 
    case when phone is null then 2 else 1 end, 
    case location when 'CA' then 1 when 'NY' then 2 when 'FL' then 3 
     when 'MA' then 4 end) as location, 
    coalesce(min(phone) keep (dense_rank first order by 
    case when phone is null then 2 else 1 end, 
    case location when 'CA' then 1 when 'NY' then 2 when 'FL' then 3 
     when 'MA' then 4 end), '---') as phone 
from directory 
where location in ('CA', 'NY', 'FL', 'MA') 
group by person; 

或者你可以MO已經CASE表達式(S)到一個單一的CTE或內嵌視圖,使他們更易於維護:

select person, 
    min(location) keep (dense_rank first order by phone_rank, location_rank) as location, 
    coalesce(min(phone) keep (dense_rank first order by phone_rank, location_rank), 
    '---') as phone 
from (
    select person, location, phone, 
    case location when 'CA' then 1 when 'NY' then 2 when 'FL' then 3 
     when 'MA' then 4 end as location_rank, 
    case when phone is null then 2 else 1 end as phone_rank 
    from directory 
    where location in ('CA', 'NY', 'FL', 'MA') 
) 
group by person; 

你還在用任何一種方法的一次打表,排名只是處理方式稍有不同,所以我不希望有性能差異(當然,最好總是檢查一下你的真實數據)。