为了在 PL/SQL 中对这些数据进行排序,使用啥数据结构?
Posted
技术标签:
【中文标题】为了在 PL/SQL 中对这些数据进行排序,使用啥数据结构?【英文标题】:What data structure to use in order to sort this data in PL/SQL?为了在 PL/SQL 中对这些数据进行排序,使用什么数据结构? 【发布时间】:2014-03-04 16:40:48 【问题描述】:这是 Oracle 11.2g。在 PL/SQL 函数中,我有一个循环,每次迭代时,我都会创建一个字符串和一个与该字符串关联的整数。该函数返回所有生成的字符串的最终连接,按字母顺序或整数值排序(取决于函数输入参数)。为了给出一个想法,我正在生成这样的东西:
Iteration String Integer
1 Oslo 40
2 Berlin 74
3 Rome 25
4 Paris 10
如果输入参数要求按字母顺序排序,则函数输出应如下所示:
Berlin, Oslo, Paris, Rome
否则,我们返回按关联整数值排序的串联字符串:
Paris, Rome, Oslo, Berlin
实现这种排序最合适的数据结构是什么?我看过集合、关联数组甚至可变数组。我有点震惊,这在 Oracle 中似乎很难实现。我看到了这个问题,但在我的情况下它不起作用,因为我需要能够按索引和值进行排序:How to sort an associative array in PL/SQL? 这种情况是否有更合适的数据结构,你将如何排序?
谢谢!
【问题讨论】:
【参考方案1】:如果您将 PL/SQL 用作 SQL 而不是像其他语言那样使用,那将非常容易。它非常具体,有时也正因为如此而非常好。
有时我真的很讨厌 PL/SQL,但这个案例绝对是关于爱情的。
看看它是多么容易:
create type it as object (
iter number,
stringval varchar2(100),
intval integer
);
create type t_it as table of it;
declare
t t_it := new t_it();
tmp1 varchar2(32767);
tmp2 varchar2(32767);
begin
t.extend(4);
t(1) := new it(1,'Oslo',40);
t(2) := new it(2,'Berlin',74);
t(3) := new it(3,'Rome',25);
t(4) := new it(4,'Paris',10);
select listagg(stringval,', ') within group (order by stringval),
listagg(stringval,', ') within group (order by intval)
into tmp1, tmp2
from table(t);
dbms_output.put_line(tmp1);
dbms_output.put_line(tmp2);
end;
/
drop type t_it;
drop type it;
在这里您可以看到必须创建全局类型的问题,这就是我讨厌它的原因。但是他们说在 Oracle 12 中可以使用本地定义的类型来完成,所以我正在等待它:)
输出是:
Berlin, Oslo, Paris, Rome
Paris, Rome, Oslo, Berlin
编辑
如果您从一开始就不知道迭代次数,唯一的方法是在每次迭代时进行扩展(这只是扩展的示例):
declare
iterator pls_integer := 1;
begin
/* some type of loop*/ loop
t.extend();
-- one way to assign
t(t.last) := new it(1,'Oslo',40);
-- another way is to use some integer iterator
t(iterator) := new it(1,'Oslo',40);
iterator := iterator + 1;
end loop;
end;
我更喜欢第二种方式,因为它更快(不会在每次迭代时计算 .last
)。
【讨论】:
精彩的回复,谢谢!有没有办法在我的 PL/SQL 函数中创建类型?我必须先单独创建它? 另外,当我在循环时,我不能使用 t.extend(4)。在循环结构中执行此操作的最佳方法是什么,每次迭代只需调用 t.extend(1)? 是的,你必须创建全局类型,这是在 11g 的查询中使用它的限制。我更新了关于循环的答案。【参考方案2】:这是一个纯 PL/SQL 实现的示例,它基于关联数组(在其他领域中也称为映射或字典)是一个按键排序的有序集合。这是我多次使用的强大功能。对于此示例中的输入数据结构,我决定使用嵌套的记录表(也称为记录列表)。
但是,在这种特殊情况下,我可能会选择与 simon 的答案类似的实现。
create or replace package so36 is
-- input data structures
type rec_t is record (
iter number,
str varchar2(20),
int number
);
type rec_list_t is table of rec_t;
function to_str(p_list in rec_list_t, p_sort in varchar2 default 'S')
return varchar2;
end;
/
show errors
create or replace package body so36 is
function to_str(p_list in rec_list_t, p_sort in varchar2 default 'S')
return varchar2 is
v_sep constant varchar2(2) := ', ';
v_ret varchar2(32767);
begin
if p_sort = 'S' then
-- create associative array (map) v_map where key is rec_t.str
-- this means the records are sorted by rec_t.str
declare
type map_t is table of rec_t index by varchar2(20);
v_map map_t;
v_key varchar2(20);
begin
-- populate the map
for i in p_list.first .. p_list.last loop
v_map(p_list(i).str) := p_list(i);
end loop;
v_key := v_map.first;
-- generate output string
while v_key is not null loop
v_ret := v_ret || v_map(v_key).str || v_sep;
v_key := v_map.next(v_key);
end loop;
end;
elsif p_sort = 'I' then
-- this branch is identical except the associative array's key is
-- rec_t.int and thus the records are sorted by rec_t.int
declare
type map_t is table of rec_t index by pls_integer;
v_map map_t;
v_key pls_integer;
begin
for i in p_list.first .. p_list.last loop
v_map(p_list(i).int) := p_list(i);
end loop;
v_key := v_map.first;
while v_key is not null loop
v_ret := v_ret || v_map(v_key).str || v_sep;
v_key := v_map.next(v_key);
end loop;
end;
end if;
return rtrim(v_ret, v_sep);
end;
end;
/
show errors
declare
v_list so36.rec_list_t := so36.rec_list_t();
v_item so36.rec_t;
begin
v_item.iter := 1;
v_item.str := 'Oslo';
v_item.int := 40;
v_list.extend(1);
v_list(v_list.last) := v_item;
v_item.iter := 2;
v_item.str := 'Berlin';
v_item.int := 74;
v_list.extend(1);
v_list(v_list.last) := v_item;
v_item.iter := 3;
v_item.str := 'Rome';
v_item.int := 25;
v_list.extend(1);
v_list(v_list.last) := v_item;
v_item.iter := 4;
v_item.str := 'Paris';
v_item.int := 10;
v_list.extend(1);
v_list(v_list.last) := v_item;
dbms_output.put_line(so36.to_str(v_list));
dbms_output.put_line(so36.to_str(v_list, 'I'));
end;
/
show errors
【讨论】:
很好的回应!谢谢你。 +1以上是关于为了在 PL/SQL 中对这些数据进行排序,使用啥数据结构?的主要内容,如果未能解决你的问题,请参考以下文章