Arrays 为了在PL/SQL中对这些数据进行排序,要使用什么数据结构?

Arrays 为了在PL/SQL中对这些数据进行排序,要使用什么数据结构?,arrays,oracle,sorting,plsql,oracle11g,Arrays,Oracle,Sorting,Plsql,Oracle11g,这是Oracle 11.2g。在PL/SQL函数中,我有一个循环,在每次迭代中,我创建一个字符串和一个与该字符串关联的整数。该函数返回所有生成字符串的最终串联,按字母顺序或整数值排序(取决于函数输入参数)。给出一个想法,我正在生成如下内容: Iteration String Integer 1 Oslo 40 2 Berlin 74 3 Rome 25 4 Paris 10 如果输

这是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
实现这种排序最合适的数据结构是什么?我看过集合、关联数组甚至varray。我有点震惊,在甲骨文中实现这一目标似乎有多么困难。我看到了这个问题,但在我的例子中它不起作用,因为我需要能够按索引和值进行排序:对于这个场景,是否有更合适的数据结构,以及您将如何排序


谢谢

如果您使用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
编辑

就您从一开始就不知道迭代的数量而言,唯一的方法是在每次迭代时进行扩展(这是扩展的唯一示例):


我更喜欢第二种方法,因为它更快(不计算每次迭代的
。last

这是一个纯PL/SQL实现的示例,它基于idea关联数组(在其他域中也称为map或dictionary)是一个按键排序的有序集合。这是我多次使用的强大功能。对于本例中的输入数据结构,我决定使用嵌套的记录表(也称为记录列表)

然而,在这种特殊情况下,我可能会选择与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

很好的回答,谢谢!有没有办法在我的PL/SQL函数中创建类型?我必须首先单独创建它?而且,由于我正在循环,所以不能使用t.extend(4)。在循环结构中实现这一点的最佳方法是什么,每次迭代只需调用t.extend(1)?是的,您必须创建全局类型,这是在11g中的查询中使用它的一个限制。我更新了关于循环的答案。反应不错!多谢各位+1.
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