达到预期结果的方法之一是使用multiset operators。
但首先我们需要将由, 分隔的字符串分成几行。其中一种方法是使用connect by 技巧:
-- Trick with building resultset from tokenized string
with dtest_string as (
select 'OK,TX,AK,TN,NC,SC,GA,FL,AL,MS' StateImpact from dual
)
select
level lvl,
substr( -- Extract part of source string
StateImpact,
-- from N-th occurence of separator
decode( level, 1, 1, instr(StateImpact,',',1,level-1)+1 ),
-- with length of substring from N-th to (N+1)-th occurence of separator or to the end.
decode( instr(StateImpact,',',1,level), 0, length(StateImpact)+1, instr(StateImpact,',',1,level) )
-
decode( level, 1, 1, instr(StateImpact,',',1,level-1)+1 )
) code
from test_string
start with
StateImpact is not null -- no entries for empty string
connect by
instr(StateImpact,',',1,level-1) > 0 -- continue if separator found on previous step
只是为了好玩:SQLFiddle 上使用 ANSI 语法的相同技巧
接下来,我们需要声明可以用来存储集合的类型:
create or replace type TCodeList as table of varchar2(100);
之后就可以构建查询了:
with all_south_list as (
-- prepare list of south states
select 'OK' as code from dual union all
select 'TX' as code from dual union all
select 'AK' as code from dual union all
select 'TN' as code from dual union all
select 'NC' as code from dual union all
select 'SC' as code from dual union all
select 'GA' as code from dual union all
select 'FL' as code from dual union all
select 'AL' as code from dual union all
select 'MS' as code from dual union all
select 'LA' as code from dual
)
select
StateImpact,
-- Make decision based on counts
case
when total_count = 0 then 'None'
when total_count = south_count then 'South'
when south_count = 0 then 'North'
else 'Both'
end RegionImpact,
total_count,
south_count,
north_count
from (
select
StateImpact,
-- count total number of states in StateImpact
cardinality(code_list) total_count,
-- count number of south states in StateImpact
cardinality(code_list multiset intersect south_list) south_count,
-- count number of non-south states in StateImpact
cardinality(code_list multiset except south_list) north_count
from (
select
StateImpact,
(
cast(multiset( -- Convert set of values into collection which acts like a nested table
select -- same trick as above
substr(
StateImpact,
decode( level, 1, 1, instr(StateImpact,',',1,level-1)+1 ),
decode( instr(StateImpact,',',1,level), 0, length(StateImpact)+1, instr(StateImpact,',',1,level) )
-
decode( level, 1, 1, instr(StateImpact,',',1,level-1)+1 )
) code
from dual
start with StateImpact is not null
connect by instr(StateImpact,',',1,level-1) > 0
) as TCodeList
)
) code_list,
-- Build collection from south states list
cast(multiset(select code from all_south_list) as TCodeList) south_list
from
CallCenter
)
)
Link to SQLFiddle