ORACLE - Значение счетчика c значение из всей таблицы (все столбцы) - PullRequest
0 голосов
/ 12 марта 2020

У меня есть таблица с именем "F_ParqueInfra", которую я хотел бы подсчитать в ней все значения, где значение равно -1.

Итак, в этой таблице 11 столбцов и 833 строки = 9,163 количество данных в этой таблице.

Я бы хотел узнать, сколько значений «-1» во всей таблице (во всех столбцах), самым простым способом. Также я сделаю это с большим количеством таблиц в моем хранилище данных.

F_ParqueInfra

Действительно, спасибо!

Ответы [ 3 ]

2 голосов
/ 13 марта 2020

Один из вариантов - использовать Dynami c SQL. Например:

SQL> select * from f_parqueinfra;

ID_USUARIO ID_EMPRESA ID_DEPARTAMENTO
---------- ---------- ---------------
       250         32              12
        -1         -1              -1
         0         -1               1
         5          2              -1

SQL> set serveroutput on;
SQL> declare
  2    l_table_name varchar2(30) := 'F_PARQUEINFRA';
  3    l_value number := -1;  -- search value
  4    l_str varchar2(200);   -- to compose SELECT statement
  5    l_cnt number := 0;     -- number of values in one column
  6    l_sum number := 0;     -- total sum of values
  7  begin
  8    for cur_r in (select table_name, column_name
  9                  from user_tab_columns
 10                  where table_name = l_table_name
 11                    and data_type = 'NUMBER'
 12                 )
 13    loop
 14      l_str := 'select count(*) from ' ||cur_r.table_name ||
 15               ' where ' || cur_r.column_name || ' = ' || l_value;
 16      execute immediate l_str into l_cnt;
 17      l_sum := l_sum + l_cnt;
 18    end loop;
 19    dbms_output.put_line('Number of ' || l_value ||' values = ' || l_sum);
 20  end;
 21  /
Number of -1 values = 5

PL/SQL procedure successfully completed.

SQL>

Если вы измените l_value (строка # 3), вы можете искать другое значение, например,

SQL> l3
  3*   l_value number := -1;  -- search value
SQL> c/-1/250
  3*   l_value number := 250;  -- search value
SQL> /
Number of 250 values = 1

PL/SQL procedure successfully completed.

SQL>

, или вы можете изменить имя таблицы ( строка # 2) и найдите другую таблицу.

По сути, вы, вероятно, захотите превратить этот анонимный код PL / SQL в функцию, которая будет принимать имя таблицы и значение поиска и возвращать количество появлений. Это не должно быть слишком сложно, поэтому я оставлю это для практики.


[РЕДАКТИРОВАТЬ: преобразование в функцию]

Хотя отнюдь не perfect , что-то вроде этого позволит вам искать некоторые числа c и строковые значения в таблицах в текущей схеме. Даты более сложные, в зависимости от форматов и т. Д. c. но - для простых случаев - этот код может быть в порядке для вас. Посмотрите:

SQL> create or replace function f_cnt (par_table_name in varchar2,
  2                                    par_data_type  in varchar2,
  3                                    par_value      in varchar2)
  4    return sys.odcivarchar2list
  5  is
  6    l_data_type varchar2(20) := upper(par_data_type);
  7    l_retval    sys.odcivarchar2list := sys.odcivarchar2list();
  8    l_str varchar2(200);   -- to compose SELECT statement
  9    l_out varchar2(200);   -- return value
 10    l_cnt number := 0;     -- number of values in one column
 11    l_sum number := 0;     -- total sum of values
 12  begin
 13    -- loop through all tables in current schema
 14    for cur_t in (select table_name
 15                  from user_tables
 16                  where table_name = upper(par_table_name)
 17                     or par_table_name is null
 18                 )
 19    loop
 20      -- reset the counter
 21      l_sum := 0;
 22      -- loop through all columns in that table
 23      for cur_c in (select column_name
 24                    from user_tab_columns
 25                    where table_name = cur_t.table_name
 26                      and data_type = l_data_type
 27                   )
 28      loop
 29        -- pay attention to search value's data type
 30        if l_data_type = 'VARCHAR2' then
 31           l_str := 'select count(*) from ' ||cur_t.table_name ||
 32                    ' where ' || cur_c.column_name || ' = ' ||
 33                    chr(39) || par_value ||chr(39);
 34        elsif l_data_type = 'NUMBER' then
 35           l_str := 'select count(*) from ' ||cur_t.table_name ||
 36                    ' where ' || cur_c.column_name || ' = ' || par_value;
 37        end if;
 38
 39        execute immediate l_str into l_cnt;
 40        l_sum := l_sum + l_cnt;
 41      end loop;
 42
 43      if l_sum > 0 then
 44         l_out := cur_t.table_name ||' has ' || l_sum ||' search values';
 45         l_retval.extend;
 46         l_retval(l_retval.count) := l_out;
 47      end if;
 48    end loop;
 49    return l_retval;
 50  end;
 51  /

Function created.

Тестирование:

SQL> select * From table(f_cnt(null, 'number', -1));

COLUMN_VALUE
-----------------------------------------------------------------
F_PARQUEINFRA has 5 search values

SQL> select * From table(f_cnt(null, 'varchar2', 'KING'));

COLUMN_VALUE
-----------------------------------------------------------------
EMP has 1 search values

SQL>
1 голос
/ 13 марта 2020

Это может быть хорошим местом для использования синтаксиса unpivot. Для этого по-прежнему требуется один раз ввести все имена столбцов, но не более.

Вот пример для 4 столбцов:

select count(*) cnt
from mytable
unpivot(myval for mycol in (col1, col2, col3, col4))
where myval = -1

В качестве бонуса вы можете легко изменить запрос на получить число -1 в столбце:

select mycol, count(*) cnt
from mytable
unpivot(myval for mycol in (col1, col2, col3, col4))
where myval = -1
group by mycol
0 голосов
/ 13 марта 2020

Это должно дать вам то, что вам нужно.

Примечания :

  1. выполняет сравнение истинных чисел c (например, будет также соответствовать -1,00) использование встроенной функции для предотвращения ошибки, если значение в сравниваемой ячейке не является числовым c. (если все ваши сравниваемые значения гарантированно равны нумерации c, встроенную функцию можно значительно упростить)
  2. ищет только типы столбцов varchar2 и number (это можно изменить при желании).

Код следует:

set serveroutput on size 10000
declare
  vMyTableName   varchar2(200)   := 'F_ParqueInfra';
  vMyValue       number          := -1;
  vSQL           varchar2(4000);
  vTotal         pls_integer;
  vGrandTotal    number(18)    := 0;
  cursor c1 is
    select * 
    from user_tab_columns
    where table_name = vMyTableName;
  vInlineFn varchar2(4000) := 'with
  function matchesMyValue(value varchar2) return pls_integer
           is
  begin
  return case
           when to_number(value) = '||vMyValue||' then
             1
           else 
             0
         end;
exception
  when value_error then
    return 0;
end;
';
begin
  for x in c1 loop
    if x.data_type in ('VARCHAR2','NUMBER') then  -- only looking in these column data types for -1 but you can flex this to suit your column type definitions
      vSQL := 'select sum(matchesMyValue('||x.column_name||')) from '||vMyTableName;
      execute immediate vInlineFn||vSQL into vTotal;
      vGrandTotal := vGrandTotal + vTotal;
    end if;
  end loop;
  dbms_output.put_line('Total cells containing -1 = '||vGrandTotal);
end;
/
...