Получение индекса элемента в коллекции PL / SQL - PullRequest
6 голосов
/ 27 января 2011

Существует ли встроенная функция для определения (первого) индекса элемента в коллекции PL / SQL?

Что-то вроде

DECLARE
  TYPE t_test IS TABLE OF VARCHAR2(1);
  v_test t_test;
BEGIN
  v_test := NEW t_test('A', 'B', 'A');
  dbms_output.put_line( 'A: ' || get_index( v_test, 'A' ) );
  dbms_output.put_line( 'B: ' || get_index( v_test, 'B' ) );
  dbms_output.put_line( 'C: ' || get_index( v_test, 'C' ) );
END;

A: 1
B: 2
C: 

Я могу использовать ассоциативные массивы, вложенные таблицы или переменные, в зависимости от необходимости. Если один и тот же элемент существует более одного раза, тогда достаточно индекса первого вхождения.


В противном случае мне пришлось бы сделать что-то вроде

CREATE FUNCTION get_index ( in_test IN t_test, in_value IN VARCHAR2 )
  RETURN PLS_INTEGER
AS
  i PLS_INTEGER;
BEGIN

i := in_test.FIRST;
  WHILE( i IS NOT NULL ) LOOP
    IF( in_test(i) = in_value ) THEN
      RETURN i;
    END IF;

    i := in_test.NEXT(i);
  END LOOP;

  RETURN NULL;

END get_index;

Ответы [ 3 ]

8 голосов
/ 27 января 2011

Не уверен, если это действительно помогает, или если вы думаете, что это более элегантно:

create type t_test as table of varchar2(1);
/

DECLARE
--TYPE t_test IS TABLE OF VARCHAR2(1);
  v_test t_test;

  function get_index(q in t_test, c in varchar2) return number is
    ind number;
  begin
    select min(rn) into ind from (
      select column_value cv, rownum rn
       from table(q) 
    )
    where cv = c;

    return ind;
  end get_index;

BEGIN
  v_test := NEW t_test('A', 'B', 'A');

  dbms_output.put_line( 'A: ' || get_index( v_test, 'A' ) );
  dbms_output.put_line( 'B: ' || get_index( v_test, 'B' ) );
  dbms_output.put_line( 'C: ' || get_index( v_test, 'C' ) );
END;
/

show errors

drop type t_test;
2 голосов
/ 28 января 2011

Я не думаю, что есть встроенная функция, которая ищет коллекцию. Однако, если вы знаете, что вам нужно много искать в коллекции, вы можете создать индекс. Добавление элемента в коллекцию будет немного дороже, но поиск элемента будет операцией O (1) (вместо O (n) для поиска методом грубой силы). Например, вы можете использовать что-то вроде этого:

SQL> DECLARE
  2     TYPE t_test IS TABLE OF VARCHAR2(1);
  3     TYPE t_test_r IS TABLE OF NUMBER INDEX BY VARCHAR2(1);
  4  
  5     v_test t_test;
  6     v_test_r t_test_r;
  7  
  8     FUNCTION get_index(p_test_r t_test_r,
  9                        p_element VARCHAR2) RETURN NUMBER IS
 10     BEGIN
 11        RETURN p_test_r(p_element);
 12     EXCEPTION
 13        WHEN no_data_found THEN
 14           RETURN NULL;
 15     END get_index;
 16  
 17     PROCEDURE add_element(p_test IN OUT t_test,
 18                           p_test_r IN OUT t_test_r,
 19                           p_element VARCHAR2) IS
 20     BEGIN
 21        p_test.extend;
 22        p_test(p_test.count) := p_element;
 23        p_test_r(p_element) := least(p_test.count,
 24                                     nvl(get_index(p_test_r, p_element),
 25                                         p_test.count));
 26     END add_element;
 27  BEGIN
 28     v_test := NEW t_test();
 29     add_element(v_test, v_test_r, 'A');
 30     add_element(v_test, v_test_r, 'B');
 31     add_element(v_test, v_test_r, 'A');
 32     dbms_output.put_line('A: ' || get_index(v_test_r, 'A'));
 33     dbms_output.put_line('B: ' || get_index(v_test_r, 'B'));
 34     dbms_output.put_line('C: ' || get_index(v_test_r, 'C'));
 35  END;
 36  /

A: 1
B: 2
C: 

PL/SQL procedure successfully completed

Вы также можете определить запись, которая содержит как массивы, так и все функции / процедуры для взаимодействия с массивами, которые будут использовать этот тип записи.

0 голосов
/ 27 января 2011

В случае сомнений обратитесь к документации;) ( здесь )

DECLARE
  TYPE aa_type_int IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
  aa_int  aa_type_int;

  PROCEDURE print_first_and_last IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE('FIRST = ' || aa_int.FIRST);
    DBMS_OUTPUT.PUT_LINE('LAST = ' || aa_int.LAST);
  END print_first_and_last;

BEGIN
  aa_int(1) := 3;
  aa_int(2) := 6;
  aa_int(3) := 9;
  aa_int(4) := 12;

  DBMS_OUTPUT.PUT_LINE('Before deletions:');
  print_first_and_last;

  aa_int.DELETE(1);
  aa_int.DELETE(4);

  DBMS_OUTPUT.PUT_LINE('After deletions:');
  print_first_and_last;
END;
/

Результат:

Before deletions:
FIRST = 1
LAST = 4
After deletions:
FIRST = 2
LAST = 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...