Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 在oracle中,如何按逗号分隔值中的属性“分组”?_Sql_Oracle_Csv_Count_Group By - Fatal编程技术网

Sql 在oracle中,如何按逗号分隔值中的属性“分组”?

Sql 在oracle中,如何按逗号分隔值中的属性“分组”?,sql,oracle,csv,count,group-by,Sql,Oracle,Csv,Count,Group By,喂,我有一张像这样的桌子 Name Pets ------------------------- Anna Cats,Dogs,Hamsters John Cats Jake Dogs,Cats Jill Parrots 我想数一数,有多少人有不同类型的宠物。输出将类似于 Pets Owners --------------- Cats 3 Dogs 2 Hamsters 1 Parrots 1 限制: 重新设计DB方案是不切实际的。如果我能做到,我

喂,我有一张像这样的桌子

Name Pets ------------------------- Anna Cats,Dogs,Hamsters John Cats Jake Dogs,Cats Jill Parrots 我想数一数,有多少人有不同类型的宠物。输出将类似于

Pets Owners --------------- Cats 3 Dogs 2 Hamsters 1 Parrots 1 限制:

重新设计DB方案是不切实际的。如果我能做到,我就不会在这里了。 所有逻辑必须在一个SQL查询中完成。 我不能在以后的代码中获取结果表并推断所有者计数。 使用内置Oracle函数是可以的,但不鼓励编写自定义函数。 Oracle版本–11及更高版本。
这是一个糟糕的设计-正如你所提到的-所以我不羡慕你不得不使用它

虽然我不想说这对于更大的数据集来说是有效的,但是你可以做你想要做的事情

假设名称列是主键或至少是唯一的:

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

这是一个糟糕的设计-正如你所提到的-所以我不羡慕你不得不使用它

虽然我不想说这对于更大的数据集来说是有效的,但是你可以做你想要做的事情

假设名称列是主键或至少是唯一的:

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

将逗号分隔的值存储在一列中是一种糟糕的设计。你应该考虑归一化数据。拥有这样的设计总是会让您在处理分隔字符串时产生开销

无论如何,作为一种解决方法,您可以使用REGEXP_SUBSTR和CONNECT BY将逗号分隔的字符串拆分为多行,然后对宠物进行计数

还有其他方法可以做到这一点,比如XMLTABLE、MODEL子句。看一看


将逗号分隔的值存储在一列中是一种糟糕的设计。你应该考虑归一化数据。拥有这样的设计总是会让您在处理分隔字符串时产生开销

无论如何,作为一种解决方法,您可以使用REGEXP_SUBSTR和CONNECT BY将逗号分隔的字符串拆分为多行,然后对宠物进行计数

还有其他方法可以做到这一点,比如XMLTABLE、MODEL子句。看一看


我的尝试,仅适用于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;

我的尝试,仅适用于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;
/用列名替换列,用表名替换表/


/用列名替换列,用表名替换表。//

此表不符合数据库表的最低要求!至少应满足第一个规范化表单。可能的宠物列表是否有限?存储在一个单独的表中?Yasserkabout:最初Pets字段是作为日志字段的,应该只显示在报告中。斯坦尼斯拉夫:有限公司?不是数学意义上的。在另一张桌子上?可以,但用户可以从该表中删除记录,但此删除操作不会也不得影响此处显示的表。该表不符合数据库表的最低要求!至少应满足第一个规范化表单。可能的宠物列表是否有限?存储在一个单独的表中?Yasserkabout:最初Pets字段是作为日志字段的,应该只显示在报告中。斯坦尼斯拉夫:有限公司?不是数学意义上的。在另一张桌子上?是的,但用户可以从该表中删除记录,但此删除不会也不得影响此处显示的表。我更喜欢此答案,因为它不使用regexI。我更喜欢此答案,因为它不使用regex