SQL Group By на выходе из пользовательской функции - PullRequest
2 голосов
/ 11 августа 2011

Возможно ли в Oracle группировать данные на выходе определенной пользователем функции? Когда я пытаюсь это сделать, я получаю ошибки, и это лучше всего иллюстрируется приведенным ниже примером:

Я пытаюсь запросить результаты в структуре таблицы, аналогичной приведенной ниже:

id   | data
1000 | {abc=123, def=234, ghi=111, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=123, def=234, ghi=222, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=123, def=434, ghi=333, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=123, def=434, ghi=444, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=123, def=634, ghi=555, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=923, def=634, ghi=666, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=923, def=434, ghi=777, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=923, def=434, ghi=888, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=923, def=234, ghi=999, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}
1000 | {abc=923, def=234, ghi=000, jkl=456, mno=567, pqr=678, stu=789, vwx=890, yza=901}

Есть другие столбцы, только не показанные. Столбец id может иметь разные значения, но в этом примере это не так. В столбце данных различаются только поля abc, def и ghi, все остальные одинаковы. Опять же, это только иллюстративно для этого примера данных.

Я написал функцию для извлечения значения, присвоенного полям в столбце данных, и он используется в следующем запросе:

select id
      ,extract_data(data,abc) as abc
      ,extract_data(data,def) as def
from   table

дает результаты:

id   | abc | def
1000 | 123 | 234
1000 | 123 | 234
1000 | 123 | 434
1000 | 123 | 434
1000 | 123 | 634
1000 | 923 | 634
1000 | 923 | 434
1000 | 923 | 434
1000 | 923 | 234
1000 | 923 | 234

В целях отчетности я хотел бы иметь возможность отображать количество записей каждого типа. В приведенном выше примере есть 6 типов, и в идеале вывод будет:

id   | abc | def | count
1000 | 123 | 234 | 2
1000 | 123 | 434 | 2
1000 | 123 | 634 | 1
1000 | 923 | 634 | 1
1000 | 923 | 434 | 2
1000 | 923 | 234 | 2

Я ожидал этого, написав SQL примерно так (и я уверен, что делал это в прошлом):

select id
      ,extract_data(data,abc) as abc
      ,extract_data(data,def) as def
      ,count(1)
from   table
group by id
        ,abc
        ,def

Это, однако, не будет работать. Oracle дает мне ошибку:

ORA-00904: "ABC": неверный идентификатор 00904. 00000 - «% s: неверный идентификатор»

Из моего первоначального исследования "Google" я понял, что, возможно, мне следует сгруппировать по столбцу, который я передаю, в мою пользовательскую функцию. Это может быть связано с тем, что SQL требует, чтобы все столбцы, не являющиеся частью агрегатной функции, должны были быть частью предложения group by.

Это будет работать для некоторых записей, однако в моем примере данных поле ghi в столбце данных отличается для каждой записи, что делает столбец данных уникальным и разрушает группу по предложению, так как задано число 1 за каждую запись.

В прошлом я использовал sybase и db2, и (настраиваясь на неудачу здесь ...) Я вполне уверен, что я смог сгруппировать по выходным данным определенной пользователем функции.

Я подумал, что может быть проблема с именами столбцов и как группа может ссылаться на них? Ссылка по номеру столбца не работает.

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

Если вам понадобится дополнительная информация, я отредактирую ее по мере необходимости или уточню в комментариях.

Спасибо, GC.

Ответы [ 3 ]

4 голосов
/ 11 августа 2011

Вы должны иметь возможность группировать по самим функциям, а не по псевдонимам

select id
      ,extract_data(data,abc) as abc
      ,extract_data(data,def) as def
      ,count(*)
from   table
group by id
        ,extract_data(data,abc)
        ,extract_data(data,def) 

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

SQL> ed
Wrote file afiedt.buf

  1  create or replace package pkg_counter
  2  as
  3    g_cnt integer := 0;
  4* end;
SQL> /

Package created.

SQL> create or replace function f1( p_arg in number )
  2    return number
  3  is
  4  begin
  5    pkg_counter.g_cnt := pkg_counter.g_cnt + 1;
  6    return mod( p_arg, 2 );
  7  end;
  8  /

Function created.

В таблице EMP 16 строк

SQL> select count(*) from emp;

  COUNT(*)
----------
        16

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

SQL> select deptno,
  2         f1( empno ),
  3         count(*)
  4    from emp
  5   group by deptno,
  6            f1( empno );

    DEPTNO  F1(EMPNO)   COUNT(*)
---------- ---------- ----------
                    1          1
        30          0          4
        20          1          1
        10          0          2
        30          1          2
        20          0          4
        10          1          1
                    0          1

8 rows selected.

SQL> begin
  2    dbms_output.put_line( pkg_counter.g_cnt );
  3  end;
  4  /
16

PL/SQL procedure successfully completed.
3 голосов
/ 11 августа 2011

Попробуйте это:

select id, abc, def, count(1)
from
(
    select 
      id,
      extract_data(data,abc) as abc,
      extract_data(data,def) as def
    from   table 
)
group by id, abc, def 
2 голосов
/ 11 августа 2011

Вы пробовали:

SELECT
    id,
    extract_data(data, abc) as abc,
    extract_data(data, def) as def,
    COUNT(1)
FROM
    table
GROUP BY
    id,
    extract_data(data, abc)
    extract_data(data, def)
...