oracle 多列中存在的 COUNT 个不同值

Posted

技术标签:

【中文标题】oracle 多列中存在的 COUNT 个不同值【英文标题】:COUNT total distinct values existing in multiple columns oracle 【发布时间】:2019-12-06 07:25:31 【问题描述】:

我有下表,我想计算跨两列的不同值。

ID_DATE     DESCRIPT1   DESCRIPT2
20191001    A           R
20191001    D           B
20191001    B           D
20191001    A           B
20191002    A           B
20191002    C           A
20191002    A           B

以下是我的查询,但结果不准确

SELECT  
COUNT(distinct DESCRIPT1 || ' - ' ||  DESCRIPT2) AS ALL_DESCRIPT,
COUNT(DISTINCT DESCRIPT1) AS DESCRIPT_A, 
COUNT(DISTINCT DESCRIPT2) AS DESCRIPT_B, 
ID_DATE FROM MY_TABLE  GROUP BY ID_DATE;

我的结果,

ALL_DESCRIPT    DESCRIPT_A  DESCRIPT_B  ID_DATE
4               3           3           20191001
2               2           2           20191002

在我的结果中,ID_DATE 20191002 的列 ALL_DESCRIPT 给我总共 2 而不是 3。它应该是 3,因为我有 A、B 和 C,在 DESCRIPT1 和 @ 列中总共是 3 987654328@ 我在哪里做错了。

以下是在 oracle 中进行测试的插入查询,以防万一。

   INSERT all 
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191001','A','R')
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191001','D','B')
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191001','B','D')
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191001','A','B')
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191002','A','B')
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191002','C','A')
   INTO SRC_DATA (ID_DATE, DESCRIPT1, DESCRIPT2) VALUES ('20191002','A','B')
   SELECT * FROM dual;

【问题讨论】:

使用 UNION 将其设为一列可能更容易:select date, descript1 from table union all select date descript2 from table 使用COUNT(distinct DESCRIPT1 || ' - ' || DESCRIPT2),您可以计算不同的对,其中您在 20191002 上只有两个:A-B 和 C-A。 【参考方案1】:

要添加到 littlefoot 的查询并给出其他列,这是一个枢轴操作,似乎:

select 
  id_date, 
  count(distinct descript) all_descript,
  count(case when descript = 'A' then 1 end) as descript_a,
  count(case when descript = 'B' then 1 end) as descript_B
from 
(
  select id_date, descript1 descript
  from src_data
  union all
  select id_date, descript2 descript 
  from src_data
) x
group by id_date
order by id_date;

您可以按照将另一个字母放入字符串中并以不同方式命名列的模式为不同的字母添加更多列。它的工作原理是当数据为例如时返回非空值时有一个案例。 A,当数据不是 A 时为空。计数仅计算非空数据。使用SUM(CASE WHEN descript = 'A' THEN 1 ELSE 0 END) 对您来说可能更有意义 - 效果相同


编辑:实际上我认为我误解了请求。试试这个:

    select 
      id_date, 
      count(distinct descript) all_descript,
      count(distinct descript1) as descript_a,
      count(distinct descript2) as descript_B
    from 
    (
      select id_date, descript1 descript, descript1, descript2
      from src_data
      union all
      select id_date, descript2 descript, null, null
      from src_data
    ) x
    group by id_date
    order by id_date

【讨论】:

【参考方案2】:

这应该可以解决您的查询,我只是使用内存表将不同的列存储在内存中,然后调用它们并以不同的形式计数。

WITH b AS  (
              SELECT id_date,DESCRIPT1  col1,descript1,descript2 FROM 
              SRC_DATA
              UNION 
            SELECT id_date,DESCRIPT2  col1,descript1,descript2 FROM SRC_DATA
           )
SELECT id_date,count(DISTINCT col1) col1,count(DISTINCT descript1) 
    descript1,count(DISTINCT descript2) descript2 
FROM b
GROUP BY id_date

【讨论】:

这似乎是一个简单的答案。如果我有超过 1000 万条记录,内存表将如何执行,它能够保存吗? @gwatene:这几乎是 Caius Jard 的第二个问题。我更喜欢他们的 1) 使用 UNION ALL 而不是 UNION 和 2) 使用空值来简化不同的计数。 @Omari Victor Omosa:无论如何,UNION 的结果都需要ALL_DESCRIPT。你也需要DISTINCT。这很贵,但就是这样。为什么不看看不同查询的解释计划,看看优化器是如何考虑成本的? UNION 删除重复项,在这种情况下,@Omari 需要区分 col1,UNION ALL 从结果中返回所有内容 @gwatene:不,无论如何你都在使用COUNT(DISTINCT),所以UNION 而不是UNION ALL 没有任何效果,除了DBMS 需要做更多的工作。此外,UNION 当然适用于整行,因此您要删除一些重复项并保留其他项。【参考方案3】:

我看不到图片,但是 - 根据您的描述,看起来像

SQL> select id_date, count(distinct descript) cnt
  2  from (select id_date, descript1 descript from src_data
  3        union all
  4        select id_date, descript2 descript from src_data
  5       )
  6  group by id_date
  7  order by id_date;

ID_DATE         CNT
-------- ----------
20191001          4
20191002          3

SQL>

如果您添加一个显示来源的列(在我的示例中为what),那么您会

SQL> select id_date,
  2    count(distinct descript) cnt,
  3    count(distinct case when what = 'A' then descript end) descript_a,
  4    count(distinct case when what = 'B' then descript end) descript_b
  5  from (select 'A' what, id_date, descript1 descript from src_data
  6        union all
  7        select 'B' what, id_date, descript2 descript from src_data
  8       )
  9  group by id_date
 10  order by id_date;

ID_DATE         CNT DESCRIPT_A DESCRIPT_B
-------- ---------- ---------- ----------
20191001          4          3          3
20191002          3          2          2

SQL>

【讨论】:

效果很好,我已经添加了文本结果。我现在如何获得包括 DESCRIPT_A 和 DESCRIPT_B 的结果? 问题,为什么你case what = 'A'或B,因为我的实际表是动态的? 我对动态一无所知。我的示例中的 A 和 B 仅显示某行属于哪个表(实际上是表中的一列)。 A = DESCRIPT1,B = DESCRIPT2。 @Omari Victor Omosa:这是因为您的结果列名称令人困惑。 DESCRIPT_ADESCRIPT_B 建议您计算“A”和“B”值,而实际上您要计算的只是不同的 DESCRIPT1DESCRIPT2 值。 Littlefoot 假设您想查找“A”和“B”值并计算它们。 @ThorstenKettner 你说得对,我实际上只是想要不同的 DESCRIPT1 和 DESCRIPT2【参考方案4】:

当遇到聚合问题时,您始终可以编写单独的聚合查询然后加入它们。在您的情况下,这可能是:

select t1.all_descript, t2.descript_a, t2.descript_b, id_date
from -- this subquery gets you the overall distinct count
(
  select id_date, count(*) as all_descript
  from 
  (
    select id_date, descript1 from mytable
    union
    select id_date, descript2 from my_table
  )
  group by id_date
) t1
join -- this subquery gets you the separate distinct counts
(
  select
    id_date,
    count(distinct descript1) as descript_a,
    count(distinct descript2) as descript_b
  from my_table
  group by id_date
) t2 using (id_date)
order by id_date;

【讨论】:

以上是关于oracle 多列中存在的 COUNT 个不同值的主要内容,如果未能解决你的问题,请参考以下文章

hive mysql count distinct 多列

Oracle的去重函数 distinct

如何将多列中的数据分离并解析成单独的行(Oracle)

多列中的不同值

SQL Server的空值处理策略

Oracle 中count 和count(*) 的区别