在 Oracle PL/SQL 中对 ref_cursor 的 DISTINCT 计数
Posted
技术标签:
【中文标题】在 Oracle PL/SQL 中对 ref_cursor 的 DISTINCT 计数【英文标题】:DISTINCT count on a ref_cursor in Oracle PL/SQL 【发布时间】:2013-09-20 10:21:40 【问题描述】:我有一些代码,我在 Oracle PL/SQL 中创建了一个引用游标,以便能够遍历结果行。该表有一个大的竖线分隔的文本字符串列,然后我循环获取 x 位置数组值
(例如:如果这些行都像 'Mike|Male|100|Yes|UK' 和 'Dave|Male|200|No|UK' 那么我有一个公式允许将数组位置传递给函数返回结果值的数组
数组位置 1 调用返回 'Mike' 和 'Dave' 数组位置 2 调用返回 'Male' 和 'Male'
如果我想拥有一个返回数组位置不同值的函数,最好的方法是什么
所以数组位置 1 调用将返回 2 数组位置 2 调用将返回 1
我对 PL/SQL 很陌生,所以请原谅这个愚蠢的问题!
不幸的是,将源表拆分为单独的列不是一种选择:-(
非常感谢
迈克
对@zero323 的回复(抱歉错过了这一点)
到目前为止的示例代码是...
FUNCTION DistinctInterfacelineValues(
inArrayPos NUMBER,
inSessionIdMIN NUMBER,
inSessionIdMAX NUMBER)
RETURN NUMBER
AS
int_cursor interfaceline_refcursor_type;
runningTotal NUMBER:=0;
tempValue NUMBER:=0;
int_record inttestintrecs%ROWTYPE;
lineLength INTEGER:=1;
distinctCount NUMBER:=0;
TYPE table_type IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
tempTable table_type;
tempTablePos INTEGER:=1;
BEGIN
OPEN int_cursor FOR SELECT * FROM inttestintrecs WHERE (sessionid>=inSessionIdMIN AND sessionid <=inSessionIdMAX);
LOOP
FETCH int_cursor INTO int_record;
EXIT
WHEN int_cursor%NOTFOUND;
lineLength := LENGTH(int_record.interfaceline) - LENGTH(REPLACE(int_record.interfaceline, '|', '')) + 1;
FOR i IN 1 .. lineLength
LOOP
IF i =inArrayPos THEN
***VALUE HERE IS 'Mike' or 'Dave' DEPENDING ON LOOP POSITION***
***I WANT TO KNOW COUNT THE DISTINCT VALUES HERE***
END IF;
END LOOP;
END LOOP;
CLOSE int_cursor;
RETURN runningTotal;
END DistinctInterfacelineValues;
【问题讨论】:
@zero323 - 主帖已修改。对于那个很抱歉。迈克 【参考方案1】:您实际上并不需要 PL/SQL。你可以使用regexp_substr
:
select count(distinct value)
from (
select regexp_substr(interfaceline, '[^|]+', 1, :arrayPos) as value
from inttestintrecs
where sessionid between :loSessId and :hiSessId
);
... 其中绑定变量是您传递给函数的值。如果你真的想要一个函数,你可以包装查询(用 tbone 的 replace
处理空值的技巧更新):
create or replace function DistinctInterfacelineValues(
inArrayPos NUMBER,
inSessionIdMIN NUMBER,
inSessionIdMAX NUMBER)
RETURN NUMBER
AS
distinctCount NUMBER;
BEGIN
select count(distinct value)
into distinctCount
from (
select trim(regexp_substr(replace(interfaceline, '|', ' |'),
'[^|]+', 1, inArrayPos)) as value
from inttestintrecs
where sessionid between inSessionIdMIN and inSessionIdMAX
);
RETURN distinctCount;
END;
/
SQL Fiddle demo.
在您发布的嵌套循环版本中,您可以维护一个按值而非数字索引的 PL/SQL 表:
...
TYPE table_type IS TABLE OF NUMBER INDEX BY VARCHAR2(100);
tempTable table_type;
tempValue VARCHAR2(100);
...
IF i = inArrayPos THEN
tempValue := regexp_substr(int_record.interfaceline, '[^|]+', 1, i);
tempTable(tempValue) := 1;
END IF;
...
RETURN tempTable.count;
...
Another Fiddle 只是为了好玩,但是拥有所有 PL/SQL 循环开销确实没有意义,尤其是在中间有 regexp_substr
时。您可以为每个值增加 tempTable
中保存的计数,这样您就知道每个值有多少,并且您也可以从 tempTable
获取实际值......但您可以从纯 SQL 版本中获取这些值同样容易(选择value, count(*)
和distinct value
)。
【讨论】:
感谢@AlexPoole,非常感谢。 如果可以的话,还有一个非常简单的问题 @Mike- 我查看了您的后续问题,但找不到快速解决方法;但 tbone 对此的回答是有效的 - Fiddle。我更新了答案以包含它。以上是关于在 Oracle PL/SQL 中对 ref_cursor 的 DISTINCT 计数的主要内容,如果未能解决你的问题,请参考以下文章