用户定义的聚合函数未被识别为“分组依据”函数

时间:2016-05-10 13:31:29

标签: sql oracle function oracle11g

select * from v$version;

BANNER
----------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0      Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

I know there are numerous ways of aggregating strings.
My needs are somewhat unique of please do not suggest alternate approaches.
I believe the following should work but it does not

我相信所有代码都遵循我在Oracle文档中找到的模式

- 创建类型

CREATE OR REPLACE TYPE t_clob_agg_comma AS OBJECT
(
  g_string  clob,
  STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_clob_agg_comma)
    RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_clob_agg_comma,
                                       value  IN      VARCHAR2 )
     RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_clob_agg_comma,
                                         returnValue  OUT  VARCHAR2,
                                         flags        IN   NUMBER)
    RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_clob_agg_comma,
                                         returnValue  OUT  CLOB,
                                         flags        IN   NUMBER)
    RETURN NUMBER,
  MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_clob_agg_comma,
                                     ctx2  IN      t_clob_agg_comma)
    RETURN NUMBER
);
/
show errors

- 创建类型主体

CREATE OR REPLACE TYPE BODY t_clob_agg_comma IS
  STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_clob_agg_comma)
    RETURN NUMBER IS
  BEGIN
    sctx := t_clob_agg_comma(NULL);
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_clob_agg_comma,
                                       value  IN      VARCHAR2)
    RETURN NUMBER IS
  BEGIN
    SELF.g_string := self.g_string || ',' || value;
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_clob_agg_comma,
                                         returnValue  OUT  VARCHAR2,
                                         flags        IN   NUMBER)
    RETURN NUMBER IS
  BEGIN
    returnValue := RTRIM(LTRIM(SELF.g_string, ','), ',');
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_clob_agg_comma,
                                         returnValue  OUT  CLOB,
                                         flags        IN   NUMBER)
    RETURN NUMBER IS
  BEGIN
    returnValue := RTRIM(LTRIM(SELF.g_string, ','), ',');
    RETURN ODCIConst.Success;
  END;
  MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_clob_agg_comma,
                                     ctx2  IN      t_clob_agg_comma)
    RETURN NUMBER IS
  BEGIN
    SELF.g_string := SELF.g_string || ',' || ctx2.g_string;
    RETURN ODCIConst.Success;
  END;
END;
/
show error

- 创建功能

CREATE OR REPLACE FUNCTION clob_agg (p_input VARCHAR2)
RETURN clob
PARALLEL_ENABLE AGGREGATE USING t_clob_agg_comma;
/
SHOW ERRORS

- 误差

SELECT department_id, clob_agg(last_name) over(order by last_name)  AS employees
FROM   demo.employee
group by department_id;

--SELECT department_id, clob_agg(last_name) over(order by last_name)  AS employees                             *
--ERROR at line 1:
--ORA-00979: not a GROUP BY expression

- 误差

SELECT department_id, clob_agg(last_name) within group order by last_name  AS employees
FROM   demo.employee
group by department_id;

- 误差

SELECT department_id, clob_agg(last_name) over(partition by department_id)  AS employees
FROM   demo.employee
group by department_id;

--SELECT department_id, clob_agg(last_name) within group order by last_name  AS employees                                    --                                                 *
--ERROR at line 1:
--ORA-00923: FROM keyword not found where expected

- 每个部门返回多行

SELECT department_id, clob_agg(last_name) over(partition by department_id order by last_name)  AS employees
FROM   demo.employee;

- 误差

SELECT department_id, clob_agg(last_name) over(partition by department_id order by last_name)  AS employees
FROM   demo.employee
group by department_id;
--SELECT department_id, clob_agg(last_name) over(partition by department_id order by last_name)  AS
--                               *
--ERROR at line 1:
--ORA-00979: not a GROUP BY expression

- 不排序,不返回department_id

SELECT clob_agg(last_name)   AS employees
FROM   demo.employee
group by department_id;

- 不排序

SELECT department_id, clob_agg(last_name)  AS employees
FROM   demo.employee
group by department_id;

2 个答案:

答案 0 :(得分:2)

所有错误都源于错误地使用聚合函数。

  • 1。错误:您没有使用clob_agg作为聚合函数,它是clob_agg(last_name),而是作为分析函数:clob_agg(last_name) over(order by last_name)。这意味着每行获得一个值,但last_name未聚合,因此不属于结果行。
  • 2。错误: WITHIN GROUP是LISTAGG特有的。我怀疑它是否适用于任何其他聚合函数。
  • 第3。错误:与1.错误相同。
  • 4。错误:与1.错误相同。

然后:

--does not sort, does not return department_id
SELECT clob_agg(last_name)   AS employees
FROM   demo.employee
group by department_id;

您没有选择department_id,因此不会自然返回。它没有排序,因为没有ORDER BY子句。

--does not sort
SELECT department_id, clob_agg(last_name)  AS employees
FROM   demo.employee
group by department_id;

同样的问题:没有ORDER BY条款。

答案 1 :(得分:0)

您似乎还不了解聚合函数(例如SUM())及其分析版本(例如SUM() OVER())之间的区别。让我试着解释一下:

您可以从表中选择每位员工的薪水。每位员工可获得一行。

select name, salary from employee;

或者您汇总了您的行,因此您不再为每位员工提供一条记录:

select avg(salary) from employee;

当您在没有GROUP BY子句的情况下聚合行(通过使用聚合函数)时,只会获得一个结果行,其中包含所有选定记录的聚合。在示例中,我们选择表中的avarage薪水。我们无法在同一结果中显示员工姓名或员工的部门,因为我们不再谈论员工,而是关于所有员工的汇总行。

使用GROUP BY我们可以按群组进行汇总,例如获得每个部门一行并显示每个部门的总计,比如每个部门的平均工资:

select department, avg(salary) from employee group by department;

我们仍然无法在结果中显示员工的姓名,因为我们不再谈论员工,而是谈论部门。每个部门可以有许多不同的员工姓名。我们可以展示的是我们分组(部门)和聚合每个部门的记录(即使用聚合函数avg(salary)min(name)等。)

通过分析功能,我们可以做一些不同的事情;我们显示最初选择的行,但在这些行上显示其他聚合。所以它是每个员工一条记录,如上面的第一个查询,但有其他列。在这里,我们显示员工的工资以及所有选定记录的平均工资:

select name, salary, avg(salary) over () from employee;

在这里我们也这样做,但是显示每个员工部门所有选定记录的平均薪水:

select name, salary, avg(salary) over (partition by department) from employee;

最后,我们将记录聚合和分析功能结合起来是极少数情况。我们显示每个部门一行(与分组汇总)以及每个部门的平均薪水,我们显示所有选定部门的最低薪水:

select department, avg(salary), min(avg(salary)) over ()
from employee 
group by department;

我们不能在此查询中使用avg(salary) over ()。我们已经使用group by department汇总了行,因此结果行中没有一个薪水可以运行我们的分析avg。我们只能在聚合上使用它,例如min(name)avg(salary)或分组列(此处为:部门)。

无论您的查询是什么,无论是GROUP BYDISTINCT还是其他:如果您希望对结果行进行排序,则必须在查询结尾处使用ORDER BY。否则,即使您的结果发生要进行排序,也不能保证这种情况。