有条件地根据字段选择整个记录

时间:2015-01-29 14:03:54

标签: sql oracle

我找到了两个解决这个问题的方法。一个很难写,另一个很难运行。我想知道是否有更好的方式让我失踪,我总是很乐意学习新的方法。

我有一个地址表,其中包含同一客户的多个记录,但不同的类型(计费,运输等)可能没有适用于所有客户的所有类型。如果他们有帐单邮寄地址我想使用,如果不使用送货地址。

对于解决方案1,我将表加入到自身中,并且每个字段都必须使用case语句来选择正确的地址。每个case语句的when部分是相同的,但必须为每个字段编写。

select
case
  when billing.customer is not null
  then billing.address
  else shipping.address
end as address
from
(
select *
from personal
where type = 'billing'
) billing
full outer join
(
select *
from personal
where type = 'shipping'
) shipping
on billing.customer = shipping.customer

http://sqlfiddle.com/#!4/6c5ff/4/0

第二种解决方案更易于编写,但执行时间更长。

select *
from personal
where type = 'billing'
union
select * from personal
where type = 'shipping'
and customer not in (
  select customer
  from personal
  where type = 'billing'
  )

http://sqlfiddle.com/#!4/6c5ff/5/0

如果有更好的方法可以学习。

3 个答案:

答案 0 :(得分:4)

我会采用第二种方法进行两次略微修改。首先,在customertype上创建索引:

create index idx_personal_type_customer on personal(type, customer_type)

使用union all代替union

select *
from personal
where type = 'billing'
union all
select * from personal
where type = 'shipping'
and customer not in (
  select customer
  from personal
  where type = 'billing'
  )

答案 1 :(得分:4)

不确定这是否更快:

select *
from (
  select *,
         row_number() over (partition by customer order by type) as rn
  from personal
  where type in ('billing', 'shipping')
) 
where rn = 1;

这是有效的,因为'billing''shipping'之前排序,因此如果两个地址都存在,则获取行号1。如果您需要包含其他地址类型,这些地址类型不会按照您希望的方式进行排序,则可以使用条件排序:

select *
from (
  select personal.*, 
         row_number() over (partition by customer 
                            order by 
                               case type 
                                  when 'postal' then 1 
                                  when 'shipping' then 2 
                                  else 3 
                            end) as rn
  from personal
  where type in ('billing', 'shipping', 'postal')
) 
where rn = 1;

这会使邮政地址的优先级高于送货地址。

答案 2 :(得分:0)

您可以简单地转动结果:

select customer,
       coalesce(max(case when type = 'billing' then address end),
                max(case when type = 'shipping' then address end)) new_address
from   personal
where  type in ('billing', 'shipping')
group by customer;

戈登早先建议的指数也不会受到影响!