2017-04-24 144 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; 

你还在用任何一种方法的一次打表,排名只是处理方式稍有不同,所以我不希望有性能差异(当然,最好总是检查一下你的真实数据)。