说,我有一张像
这样的表Name Pets ------------------------- Anna Cats,Dogs,Hamsters John Cats Jake Dogs,Cats Jill Parrots
我想算一下,有多少人有不同类型的宠物。输出类似于
Pets Owners --------------- Cats 3 Dogs 2 Hamsters 1 Parrots 1
限制:
答案 0 :(得分:2)
这是一个糟糕的设计 - 正如你所提到的 - 所以我不羡慕你不得不使用它!
你可以做你想做的事情,虽然我不想说它会对大型数据集有效!
假设name
列是主键(或至少是唯一的):
with t1 as (select 'Anna' name, 'Cats,Dogs,Hamsters' pets from dual union all
select 'John' name, 'Cats' pets from dual union all
select 'Jake' name, 'Dogs,Cats' pets from dual union all
select 'Jill' name, 'Parrots' pets from dual)
select pet pets,
count(*) owners
from (select name,
regexp_substr(pets, '(.*?)(,|$)', 1, level, null, 1) pet
from t1
connect by prior name = name
and prior sys_guid() is not null
and level <= regexp_count(pets, ',') + 1)
group by pet
order by owners desc, pet;
PETS OWNERS
---------- ----------
Cats 3
Dogs 2
Hamsters 1
Parrots 1
答案 1 :(得分:1)
将以逗号分隔的值存储在单列中是一种糟糕的设计。您应该考虑规范化数据。有这样的设计总会让你有一个操纵分隔字符串的开销。
无论如何,作为一种解决方法,您可以使用 REGEXP_SUBSTR 和 CONNECT BY 将逗号分隔的字符串拆分为多行,然后计算宠物。
还有其他方法可以做到这一点,例如 XMLTABLE , MODEL 子句。请查看 split the comma-delimited string into multiple rows 。
SQL> WITH sample_data AS(
2 SELECT 'Anna' NAME, 'Cats,Dogs,Hamsters' pets FROM dual UNION ALL
3 SELECT 'John' NAME, 'Cats' pets FROM dual UNION ALL
4 SELECT 'Jake' NAME, 'Dogs,Cats' pets FROM dual UNION ALL
5 SELECT 'Jill' NAME, 'Parrots' pets FROM dual
6 )
7 -- end of sample_data mimicking a real table
8 SELECT pets,
9 COUNT(*) cnt
10 FROM
11 (SELECT trim(regexp_substr(t.pets, '[^,]+', 1, lines.COLUMN_VALUE)) pets
12 FROM sample_data t,
13 TABLE (CAST (MULTISET
14 (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(t.pets, ',')+1
15 ) AS sys.odciNumberList ) ) lines
16 ORDER BY NAME,
17 lines.COLUMN_VALUE
18 )
19 GROUP BY pets
20 ORDER BY cnt DESC;
PETS CNT
------------------ ----------
Cats 3
Dogs 2
Hamsters 1
Parrots 1
SQL>
答案 2 :(得分:1)
我的尝试,只有substr和instr:)
with a as (
select 'Anna' as name, 'Cats,Dogs,Hamsters' as pets from dual union all
select 'John', 'Cats' from dual union all
select 'Jake', 'Dogs,Cats' from dual union all
select 'Jill', 'Parrots' from dual
),
b as(
select name, pets, substr(pets, starting_pos, ending_pos - starting_pos) pet
from (
select name, pets,
decode(lvl, 1, 0, instr(a.pets,',',1,lvl-1))+1 starting_pos,
instr(a.pets,',',1,lvl) ending_pos
from (select name, pets||',' pets from a
)a
join (select level lvl from dual connect by level < 10)
on instr(a.pets,',', 1, lvl) > 0
)
)
--select * from b
select pet, count(*) from b group by pet;
答案 3 :(得分:0)
select x pets ,count(x) Owners from (
select extractvalue(value(x), '/b') x
from (select yourcolumn as str from yourtable) t,
table(
xmlsequence(
xmltype('<a><b>' || replace(str, ',', '</b><b>') || '</b></a>' ).extract('/*/*')
)
) x)
group by x;
/ 用您的列名(宠物)替换您的列,并使用您的表名替换您的列。 /