динамические столбцы в oracle с использованием sql

у меня есть следующий пример таблицы. Thera может быть неограниченным филиалом и клиентами. Мне нужно сгруппировать эти ветви и подсчитать их клиентов, а затем показать, что это с разными столбцами.

BRANCHNAME  CUSTOMERNO
100         1001010
100         1001011
103         1001012
104         1001013
104         1001014
104         1001015
105         1001016
105         1001017
106         1001018

обратите внимание, что могут быть неограниченные ветви и клиенты, запрос должен работать не только в этом случае.

В этом случае принимается результат:

100 103 104 105 106
 2   1   3   2   1

пример данных SQL

    select '100' BranchName,'1001010' CustomerNo from dual   UNION ALL 
    select '100' BranchName,'1001011' CustomerNo from dual   UNION ALL 
    select '103' BranchName,'1001012' CustomerNo from dual   UNION ALL 
    select '104' BranchName,'1001013' CustomerNo from dual   UNION ALL 
    select '104' BranchName,'1001014' CustomerNo from dual   UNION ALL 
    select '104' BranchName,'1001015' CustomerNo from dual   UNION ALL 
    select '105' BranchName,'1001016' CustomerNo from dual   UNION ALL 
    select '105' BranchName,'1001017' CustomerNo from dual   UNION ALL 
    select '106' BranchName,'1001018' CustomerNo from dual   

6 ответов


Я думаю, что можно, хотя и довольно сложно, написать конвейерная табличная функция, возвращающая переменную structure. Функция таблицы конвейера будет использовать интерфейс картриджа данных Oracle и магию типа AnyDataSet для возврата динамической структуры во время выполнения. Затем вы можете использовать это в последующих инструкциях SQL, как если бы это была таблица, т. е.

SELECT *
  FROM TABLE( your_pipelined_function( p_1, p_2 ));

еще несколько ссылок, в которых обсуждается тот же пример реализации

  • динамический поворот SQL
  • на реализация интерфейсного подхода раздел руководства разработчика Oracle Data Cartridge
  • Method4. после загрузки и установки кода с открытым исходным кодом PL / SQL, вот полная реализация:

    --Create sample table.
    create table branch_data as
    select '100' BranchName,'1001010' CustomerNo from dual   UNION ALL 
    select '100' BranchName,'1001011' CustomerNo from dual   UNION ALL 
    select '103' BranchName,'1001012' CustomerNo from dual   UNION ALL 
    select '104' BranchName,'1001013' CustomerNo from dual   UNION ALL 
    select '104' BranchName,'1001014' CustomerNo from dual   UNION ALL 
    select '104' BranchName,'1001015' CustomerNo from dual   UNION ALL 
    select '105' BranchName,'1001016' CustomerNo from dual   UNION ALL 
    select '105' BranchName,'1001017' CustomerNo from dual   UNION ALL 
    select '106' BranchName,'1001018' CustomerNo from dual;
    
    --Create a dynamic pivot in SQL.
    select *
    from table(method4.dynamic_query(
        q'[
            --Create a select statement
            select
                --The SELECT:
                'select'||chr(10)||
                --The column list:
                listagg(
                    replace(q'!sum(case when BranchName = '#BRANCH_NAME#' then 1 else 0 end) "#BRANCH_NAME#"!', '#BRANCH_NAME#', BranchName)
                    , ','||chr(10)) within group (order by BranchName)||chr(10)||
                --The FROM:
                'from branch_data' v_sql
            from
            (
                --Distinct BranchNames.
                select distinct BranchName
                from branch_data
            )
        ]'
    ));
    

Если вы просто хотите сообщить результаты где-нибудь, вы можете использовать курсор для инструкции select:

select branchname, count(*) from test group by branchname order by branchname asc;

цикл через курсор вы можете получить свои значения.

вот мой пример:

declare
  v_b varchar2(1000);
  v_t varchar2(1000);
begin
  for i in (select branchname, count(*) total from test group by branchname order by branchname asc)
  loop
      v_b := v_b || i.branchname || ' ';
      v_t := v_t || i.total || '   ';     
  end loop;

  dbms_output.put_line(v_b);
  dbms_output.put_line(v_t);
end;

Это получит его в строках (а не столбцах):

SELECT branchname,
       COUNT( DISTINCT customerno ) AS customers
FROM   your_table
GROUP BY branchname;

(Примечание: Вы можете не указывать DISTINCT ключевое слово, если не будет повторений branchname, customerno пара.)

не зная, какие имена ветвей вы можете сделать только динамический пивот.

было бы намного проще взять вывод вышеуказанного запроса (в формате строки) и транспонировать его в любом интерфейсе, который вы используете для доступа к база данных.

из комментариев:

мне нужен отчет в этом формате, и не хочу писать какое-то приложение , хочет сделать с sql для легкого экспорта, чтобы преуспеть в таком формате

нет, вам это не нужно в формате столбца в SQL. Вы можете поместить его в excel в формате строки, а затем использовать excel TRANSPOSE функция для преобразования его (очень просто) в столбцы без необходимости реализации сложного динамического решения SQL.


Как насчет этого решения. Без создания таблицы, просто установите параметр v_sql.

SET SERVEROUTPUT ON SIZE 100000

DECLARE
   v_cursor    sys_refcursor;

   CURSOR get_columns
   IS
      SELECT EXTRACTVALUE (t2.COLUMN_VALUE, 'node()') VALUE
        FROM (SELECT *
                FROM TABLE (XMLSEQUENCE (v_cursor))) t1,
             TABLE (XMLSEQUENCE (EXTRACT (t1.COLUMN_VALUE, '/ROW/node()'))) t2;

   v_column    VARCHAR2 (1000);
   v_value     VARCHAR2 (1000);
   v_counter   NUMBER (3)      := 0;
   v_sql       VARCHAR2 (4000);
BEGIN
   v_sql :=
         'SELECT   branchname, COUNT (DISTINCT customerno) AS customers'
      || ' FROM (SELECT 100 branchname, 1001010 customerno'
      || ' FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 100 branchname, 1001011 customerno'
      || ' FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 103 branchname, 1001012 customerno'
      || ' FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 104 branchname, 1001013 customerno'
      || ' FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 104 branchname, 1001014 customerno'
      || '   FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 104 branchname, 1001015 customerno'
      || '  FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 105 branchname, 1001016 customerno'
      || '   FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 105 branchname, 1001017 customerno'
      || '   FROM DUAL'
      || ' UNION ALL'
      || ' SELECT 106 branchname, 1001018 customerno'
      || '   FROM DUAL)'
      || ' GROUP BY branchname';

   OPEN v_cursor FOR v_sql;

   FOR v_record IN get_columns
   LOOP
      IF v_counter = 0
      THEN
         v_column := v_column || v_record.VALUE || ' ';
         v_counter := 1;
      ELSIF v_counter = 1
      THEN
         v_value := v_value || v_record.VALUE || '   ';
         v_counter := 0;
      END IF;
   END LOOP;

   DBMS_OUTPUT.put_line (v_column);
   DBMS_OUTPUT.put_line (v_value);
END;
/

и вывода

100 105 104 103 106 
2   2   3   1   1  

with src as
(select '100' BranchName,'1001010' CustomerNo from dual   UNION ALL 
select '100' BranchName,'1001011' CustomerNo from dual   UNION ALL 
select '103' BranchName,'1001012' CustomerNo from dual   UNION ALL 
select '104' BranchName,'1001013' CustomerNo from dual   UNION ALL 
select '104' BranchName,'1001014' CustomerNo from dual   UNION ALL 
select '104' BranchName,'1001015' CustomerNo from dual   UNION ALL 
select '105' BranchName,'1001016' CustomerNo from dual   UNION ALL 
select '105' BranchName,'1001017' CustomerNo from dual   UNION ALL 
select '106' BranchName,'1001018' CustomerNo from dual )
SELECT * FROM
(select BranchName from src)
PIVOT XML 
(COUNT(*) FOR (BranchName) 
IN 
(SELECT DISTINCT BranchName FROM SRC))

этот запрос дает выходные данные в формате xml. Все xml-данные будут содержаться в поле результатов запроса (Запрос имеет только одну строку-вывод столбца sinlge). Следующим шагом является анализ xml-данных и их отображение в табличной форме.


Вы можете использовать этот вариант:

SELECT branchname, count(*) 
FROM test 
GROUP BY branchname

вообще не профессионально использовать выбор для каждого номера в branchname.