#plsql
Вопрос:
У меня есть такая структура таблицы в моей базе данных
Теперь я хочу, чтобы все значения внутри него были в ассоциативном массиве, который индексируется типом job_id%, который является varchar2, поэтому я сначала создал этот анонимный блок, прежде чем создавать процедуру для его тестирования, и я хочу заполнить свой ассоциативный массив результатами:
DECLARE
TYPE jobs_tab_type IS TABLE OF jobs%rowtype INDEX BY jobs.job_id%type;
jobstab jobs_tab_type;
BEGIN
FOR rec IN (SELECT * FROM jobs)
LOOP
jobstab(rec.job_id) := rec.job_id;
END LOOP;
END;
Я точно знаю, что это неправильный способ сделать это, поскольку я столкнулся с этой ошибкой: PLS-00382: expression is of wrong type
, но в то же время я не знаю, есть ли какой-либо правильный способ сделать это. Я видел документацию, но во всех примерах использовалась определяемая пользователем строка, которая будет содержать job_id , но проблема в том, что мне нужно, чтобы job_id был проиндексирован, а не определяемая пользователем строка. Есть ли какой-либо способ исправить эту проблему в PL / SQL?
Ответ №1:
Вам не нужен индекс by INDEX BY jobs.job_id%type
. Это делает ваш код более сложным. INDEX BY
Определяет индекс коллекции — то есть символ, используемый для обозначения позиции в коллекции. Это не обязательно должен быть столбец из таблицы, из которой вы берете %rowtype . Обычно INDEX BY VARCHAR2
используется, если вы хотите ссылаться на коллекцию на основе значимой строки, например capitals('United States') = 'Washingston'
Теперь, что касается вашего вопроса. Вот ответ на первоначальный вопрос:
create table jobs
(job_id VARCHAR2(10)
,job_title VARCHAR2(30)
,min_salary NUMBER
,max_salary NUMBER
);
INSERT INTO jobs (job_id, job_title, min_salary, max_salary) VALUES ('a','CLERK',100,500);
INSERT INTO jobs (job_id, job_title, min_salary, max_salary) VALUES ('b','PRESIDENT',1000,5000);
INSERT INTO jobs (job_id, job_title, min_salary, max_salary) VALUES ('c','SALESMAN',500,800);
DECLARE
TYPE jobs_tab_type IS TABLE OF jobs%rowtype INDEX BY jobs.job_id%type;
jobstab jobs_tab_type;
l_idx VARCHAR2(100);
BEGIN
FOR rec IN (SELECT * FROM jobs)
LOOP
jobstab(rec.job_id) := rec;
END LOOP;
l_idx := jobstab.FIRST;
WHILE (l_idx IS NOT NULL) LOOP
dbms_output.put_line(l_idx ||': '||jobstab(l_idx).job_title);
l_idx := jobstab.NEXT(l_idx);
END LOOP;
END;
/
a: CLERK
b: PRESIDENT
c: SALESMAN
Обратите внимание, что в этом блоке немного утомительно перебирать элементы, просто потому, что индекс не является целым числом. Теперь давайте рассмотрим ту же функциональность, но с использованием INDEX BY BINARY_INTEGER
:
DECLARE
TYPE jobs_tab_type IS TABLE OF jobs%rowtype INDEX BY BINARY_INTEGER;
jobstab jobs_tab_type;
l_idx NUMBER := 1;
BEGIN
-- example 1: using a cursor for loop
-- FOR rec IN (SELECT * FROM jobs)
-- LOOP
-- jobstab(l_idx) := rec;
-- l_idx := l_idx 1;
-- END LOOP;
-- example 2: using bulk collect
SELECT * BULK COLLECT INTO jobstab FROM jobs;
FOR r IN 1 .. jobstab.COUNT LOOP
dbms_output.put_line(r ||': '||jobstab(r).job_title);
END LOOP;
END;
/
1: CLERK
2: PRESIDENT
3: SALESMAN
Проще перебирать значения коллекции из-за числового индекса, и он также может быть неявно присвоен, используя BULK COLLECT
оператор.
Ответ №2:
Значением вашего ассоциативного массива является вся запись. Следовательно, просто удалите .job_id
из этой строки вашего кода.
jobstab(rec.job_id) := rec.job_id;
Другими словами, строка должна быть
jobstab(rec.job_id) := rec;
Обратитесь к этой скрипке db<>