Oracle多个CASE语句评估为true

时间:2017-04-24 16:18:48

标签: oracle case

我认为一旦CASE找到匹配,它就会破坏并返回第一场比赛。但是,我从case语句中获得所有匹配。 e.g。

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

由于PERSON可以在每个州都有电话号码,我想要的是找到的第一个电话号码,基本上按州的顺序“排名”。我得到的是找到的所有电话号码。

... THX

3 个答案:

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

答案 1 :(得分:0)

@ TimBielgeleisen的CTE方法可能更容易遵循和维护,但你可以使用keep dense_rank在没有任何CTE的情况下做同样的事情,尽管你必须重复案例表达:

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;

或者您可以将案例表达式移动到单个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;

您仍然使用这些方法进行过一次排名,排名的处理方式略有不同,因此我不会期望性能差异(但总是最好检查您的实际数据,当然)。

答案 2 :(得分:0)

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