【问题标题】:Count specific match from complete table data in Oracle DB从 Oracle DB 中的完整表数据中计算特定匹配
【发布时间】:2021-10-27 07:32:09
【问题描述】:

我想从下表数据中计算“是”和“否”,而不考虑列。

Oracle 数据库表:

预期输出:

它来自哪一列并不重要。我只想计算是和否的总数。 我尝试使用 pivot 但找不到如何将其用于多个列的方法。

请帮忙。

【问题讨论】:

  • 我想我找到了一种更通用的方法。查看我的更新答案。

标签: sql oracle


【解决方案1】:

如果它必须是动态的,那么......它必须是动态的,这意味着PL/SQL 是一个选项来做你想做的事。这是一个例子:

循环遍历名称作为参数传递的表中的所有列并计算作为第二个参数传递的值的数量的函数:

SQL> create or replace function f_yes_no
  2    (par_table_name in varchar2, par_yes_no in varchar2)
  3    return number
  4  is
  5    l_cnt  number;
  6    retval number := 0;
  7  begin
  8    for cur_r in (select column_name from user_tab_columns
  9                  where table_name = dbms_assert.sql_object_name(par_table_name)
 10                    and data_type like '%CHAR%'
 11                 )
 12    loop
 13      execute immediate
 14        'select count(*) from ' || dbms_assert.sql_object_name(par_table_name) ||
 15        '  where ' || cur_r.column_name || ' = ' ||
 16        dbms_assert.enquote_literal(par_yes_no)
 17        into l_cnt;
 18      retval := retval + l_cnt;
 19    end loop;
 20    return retval;
 21  end;
 22  /

Function created.

SQL>

测试:样本表:

对于示例表:

SQL> select * from test;

ZING  PLING COL3  BOING
----- ----- ----- -----
Yes   No    Yes   No
Yes   No    No    No
No    No    Yes   No

SQL> select f_yes_no('TEST', 'Yes') cnt_yes,
  2         f_yes_no('TEST', 'No' ) cnt_no
  3  from dual;

   CNT_YES     CNT_NO
---------- ----------
         4          8

SQL>

它有什么好处?您可以将该函数重用于另一个表中的其他字符串,例如Scott 的EMP 表中有多少个MANAGER

SQL> select ename, job from emp order by job;

ENAME      JOB
---------- ---------
SCOTT      ANALYST
FORD       ANALYST
MILLER     CLERK
JAMES      CLERK
SMITH      CLERK
ADAMS      CLERK
BLAKE      MANAGER
JONES      MANAGER
CLARK      MANAGER
KING       PRESIDENT
TURNER     SALESMAN
MARTIN     SALESMAN
WARD       SALESMAN
ALLEN      SALESMAN

14 rows selected.

SQL> select f_yes_no('EMP', 'MANAGER') cnt_mgr from dual;

   CNT_MGR
----------
         3

SQL>

【讨论】:

    【解决方案2】:

    UNPIVOT 子句?

    SELECT
      SUM(DECODE(v, 'Yes', 1)) "Yes",
      SUM(DECODE(v, 'No', 1)) "No"
    FROM t
    UNPIVOT (
      v FOR value_type IN (c1, c2, c3, c4, c5)
    );
    

    db<>fiddle

    更通用的方式:

    SELECT
     SUM(DECODE(yes_no, 'Yes', 1)) "Yes",
     SUM(DECODE(yes_no, 'No', 1)) "No"
    FROM (
      SELECT
        x.yes_no.EXTRACT(c.column_name || '/text()').getStringVal() yes_no
      FROM
        XMLTABLE ('/ROWSET/ROW'
                  PASSING XMLTYPE(dbms_xmlgen.getxml('SELECT * FROM t'))
                  COLUMNS
                    yes_no XMLTYPE PATH '*[text() = ("Yes", "No")]') x
      CROSS JOIN user_tab_columns c
      WHERE
        c.table_name = 'T' AND
        column_name LIKE 'C%'
    ) t;
    

    db<>fiddle

    所有功劳必须归https://stackoverflow.com/a/45866854/3350428

    【讨论】:

      【解决方案3】:

      一种方法是使用横向连接:

      select sum(case when col = 'Yes' then 1 else 0 end) as num_yes,
             sum(case when col = 'No' then 1 else 0 end) as num_no
      from t cross join lateral
           (select t.column1 as col from dual union all
            select t.column2 from dual union all
            select t.column3 from dual union all
            select t.column4 from dual union all
            select t.column5 from dual
           ) t
      
        
      

      【讨论】:

      • 谢谢。只是想知道,如果假设有50列,那么我们还必须写下每一列的名称吗?实际上,我想做一个独立于列名的查询。
      • @HavishaaSharma 。 . .您可以使用电子表格或查询来生成代码。也就是说,如果你有五十个这样的列,你似乎有问题。我猜测不同的数据模型会有所帮助——例如每个“YES”值一行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2015-12-24
      • 1970-01-01
      相关资源
      最近更新 更多