我找到了两个解决这个问题的方法。一个很难写,另一个很难运行。我想知道是否有更好的方式让我失踪,我总是很乐意学习新的方法。
我有一个地址表,其中包含同一客户的多个记录,但不同的类型(计费,运输等)可能没有适用于所有客户的所有类型。如果他们有帐单邮寄地址我想使用,如果不使用送货地址。
对于解决方案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
如果有更好的方法可以学习。
答案 0 :(得分:4)
我会采用第二种方法进行两次略微修改。首先,在customer
和type
上创建索引:
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;
戈登早先建议的指数也不会受到影响!