使用 Select Count 的 Oracle SQL 函数为每一行返回重复的答案

Oracle SQL function using Select Count returns duplicate answer for every row

提问人:Rhys Miller 提问时间:9/10/2023 更新时间:9/11/2023 访问量:42

问:

尝试做一个简单的用户函数,我得到年龄> 100 的人数。

这是我现在的桌子

从人民中选择 *

**NAME**      **AGE**
----------------------
Joe Bloggs  12
Paul Smith  15
Jonah James 534
Mika Rive   31
Hannah Bananas  56
Harry Heelz 4
Brian Bolton    232
Jack Ripper 123

我目前正在尝试实现用户功能,其中输出是单行,年龄大于 100 的总人数。

这是我尝试制作的函数

create or replace function agetest return number is
v_count number;

begin
    select count(age) into v_count
    from persons
    where  age > 100;
    
        return v_count;
end;
 

当我直接执行SQL查询时,我得到了正确的答案

select count(age) from persons where age > 100;

计数(AGE)
1 3

但是当我运行该函数时

select agetest from persons;

我得到以下输出:

年龄测试
1 3
2 3
3 3
4 3
5 3
6 3
7 3
8 3

只是在寻找有关为什么输出对每行显示相同结果的指导。

我对该函数的理想输出是:

年龄测试
1 3
SQL Oracle 函数 选择 计数

评论

0赞 Jonas Metzler 9/10/2023
由于您不在查询中使用子句,因此将为表中的每一行生成结果。你使用函数的事实并不重要,因为查询不知道你的函数将做什么。为什么要使用函数?这在我看来是绝对错误的。只需编写一个查询,工作就完成了。如果要使用该功能,请尝试从表中选择,而不是从表中选择。WHEREdualpersons
0赞 Rhys Miller 9/10/2023
这更像是我为学校提出的一个更大的问题,我只是想先弄清楚基础知识。
0赞 Jonas Metzler 9/10/2023
好吧,在我看来,最基本的事情之一就是更喜欢纯查询而不是函数或过程。我经常看到人们使用它们,尽管不是必需的。我认为这使事情变得不必要复杂,因为我们不直接看到查询,而只是函数或过程调用,需要检查那里执行的内容。因此,我建议尽可能避免使用函数和程序。但好吧,这只是我的观点。也许我错了。

答:

0赞 Tim Biegeleisen 9/10/2023 #1

尝试针对以下条件执行该函数:DUAL

SELECT agetest FROM dual;

在 Oracle 中,表是一种虚拟表,其中只有一条记录。DUAL

评论

0赞 Rhys Miller 9/10/2023
这似乎奏效了!谢谢你:)
0赞 Jonas Metzler 9/10/2023
附带说明:在 Oracle 23c 中,我们不再需要使用该表。我们可以不带任何子句地写。就像我们在任何其他 RDBMS 中一样。这张表是一些非常奇怪的神谕,将变得过时。dualSELECT xyFROMdual
0赞 Jonas Metzler 9/10/2023
我说的是,我们可以像在常见的RDBMS中不使用表或子句一样编写查询。现在(或将来)我们也可以在 Oracle 中做到这一点,并且不需要表。SELECT 1FROMdual
0赞 jarlh 9/10/2023
@JonasMetzler,哎呀。我看错了。我的错。
1赞 MT0 9/11/2023 #2

执行查询时:

select count(age) from persons where age > 100;

将所有行聚合为一行。

当您执行以下操作时:

select agetest from persons;

您没有执行第一个查询,因为这是一个标量函数(不是聚合函数),并且您有效地执行了:agetest

SELECT (select count(age) from persons where age > 100) FROM persons;

也就是说,对于中的每一行执行子查询;这就是为什么你得到函数的返回值对每个人重复,输出为:persons

(SELECTCOUNT(AGE)FROMPERSONSWHEREAGE>100)
3
3
3
3
3
3
3
3

如果要获取一次函数值,则只需使用只有一行的表(例如):DUAL

SELECT agetest FROM dual;

或者,您可以将函数从标量函数更改为用户定义的聚合函数:

CREATE OR REPLACE TYPE CountGreaterThan100Type AS OBJECT(
  cnt NUMBER(10,0),

  STATIC FUNCTION ODCIAggregateInitialize(
    ctx         IN OUT CountGreaterThan100Type
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateIterate(
    self        IN OUT CountGreaterThan100Type,
    value       IN     NUMBER
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateTerminate(
    self        IN OUT CountGreaterThan100Type,
    returnValue    OUT NUMBER,
    flags       IN     NUMBER
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateMerge(
    self        IN OUT CountGreaterThan100Type,
    ctx         IN OUT CountGreaterThan100Type
  ) RETURN NUMBER
);
/

CREATE OR REPLACE TYPE BODY CountGreaterThan100Type
IS
  STATIC FUNCTION ODCIAggregateInitialize(
    ctx         IN OUT CountGreaterThan100Type
  ) RETURN NUMBER
  IS
  BEGIN
    ctx := CountGreaterThan100Type( 0 );
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateIterate(
    self        IN OUT CountGreaterThan100Type,
    value       IN     NUMBER
  ) RETURN NUMBER
  IS
  BEGIN
    IF value > 100 THEN
      self.cnt := self.cnt + 1;
    END IF;
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateTerminate(
    self        IN OUT CountGreaterThan100Type,
    returnValue    OUT NUMBER,
    flags       IN     NUMBER
  ) RETURN NUMBER
  IS
  BEGIN
    returnValue := self.cnt;
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateMerge(
    self        IN OUT CountGreaterThan100Type,
    ctx         IN OUT CountGreaterThan100Type
  ) RETURN NUMBER
  IS
  BEGIN
    self.cnt := self.cnt + ctx.cnt;
    RETURN ODCIConst.SUCCESS;
  END;
END;
/

CREATE FUNCTION CountGreaterThan100( value NUMBER )
RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING CountGreaterThan100Type;
/

然后:

SELECT CountGreaterThan100(age) FROM persons;

输出:

COUNTGREATERTHAN100(年龄)
3

小提琴