SQL Group By On用户定义函数的输出

时间:2011-08-11 16:32:24

标签: sql oracle function group-by user-defined-functions

在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:无效标识符”

从我对“谷歌”的初步研究中,我看到我应该在我传递到用户定义函数的列上进行分组。这可能是由于SQL要求所有不属于聚合函数的列都需要成为group by子句的一部分。

这适用于某些记录,但是在我的数据示例中,数据列中的字段ghi对于每个记录都是不同的,因此使数据列唯一,并且破坏group by子句,因为计数为1对于每条记录。

我过去曾经使用过sybase和db2,并且(在这里设置了一个秋天......)我很确定我能够在用户定义函数的输出上进行分组。

我认为列的命名可能存在问题,以及如何通过组引用它们?按列号引用无效。

我已经尝试过各种各样的组合,并且无法让它发挥作用,所以我很感激你们可以给予的任何见解。

如果您需要更多信息,我会根据需要进行编辑或在评论中进行澄清。

谢谢, GC

3 个答案:

答案 0 :(得分:4)

您应该能够按功能本身进行分组,而不是使用别名

进行分组
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.

答案 1 :(得分:3)

试试这个:

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 :(得分:2)

你试过了吗?

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)