2010-04-26 21 views
10

Tôi muốn thực hiện truy vấn SQL bên trong PL/SQL và điền kết quả vào một mảng kết hợp, trong đó một trong các cột trong SQL trở thành khóa trong mảng kết hợp. Ví dụ, nói rằng tôi có một bảng với các cột PersonThu thập số lượng lớn PL/SQL vào mảng kết hợp với khóa thưa

PERSON_ID INTEGER  PRIMARY KEY 
PERSON_NAME VARCHAR2(50) 

... và giá trị như:

PERSON_ID | PERSON_NAME 
------------------------ 
6   | Alice 
15   | Bob 
1234  | Carol 

Tôi muốn số lượng lớn thu thập bảng này thành một TABLE OF VARCHAR2(50) INDEX BY INTEGER như rằng chìa khóa 6 trong kết này mảng có giá trị Alice và v.v. Điều này có thể được thực hiện trong PL/SQL không? Nếu vậy, làm thế nào?

Trả lời

14

Không, bạn phải sử dụng 2 bộ sưu tập (id, tên) hoặc loại có loại phần tử là bản ghi.

Dưới đây là một ví dụ của cái sau:

cursor getPersonsCursor is 
    SELECT ID, Name 
    FROM Persons 
    WHERE ...; 

    subtype TPerson is getPersonsCursor%rowtype; 
    type TPersonList is table of TPerson; 
    persons TPersonList; 
begin 

open getPersonsCursor; 
fetch getPersonsCursor 
    bulk collect into persons; 
close getPersonsCursor; 

if persons.Count > 0 then 
    for i in persons.First .. persons.Last loop 
    yourAssocArray(persons(i).ID) := persons(i).Name; 
    end loop; 
end if; 
+1

+1. Nếu số hàng là (hoặc sẽ bao giờ) rất lớn, hãy xem xét sử dụng mệnh đề LIMIT để ngăn tiêu thụ bộ nhớ PGA quá mức. –

+0

vâng, tôi cũng làm như vậy để cho phép mở rộng quy mô tốt hơn. Nghĩ rằng nó sẽ là một chút over-the-top, mặc dù. –

6

Nếu chúng ta muốn xác định giá trị trong chỉ số một mảng kết hợp của sau đó, chúng tôi đã sử dụng cú pháp sau:

SQL> declare 
    2  type n_array is table of varchar2(30) 
    3   index by binary_integer; 
    4  emp_names n_array; 
    5 begin 
    6  for r in (select ename, empno from emp) 
    7  loop 
    8   emp_names(r.empno) := r.ename; 
    9  end loop; 
10 
11  dbms_output.put_line('count='||emp_names.count() 
12        ||'::last='||emp_names.last()); 
13  dbms_output.put_line(emp_names(8085)); 
14 
15 end; 
16/
count=19::last=8085 
TRICHLER 

PL/SQL procedure successfully completed. 

SQL> 

Chúng tôi thể populate mảng kết hợp với thu thập hàng loạt nhưng chỉ khi chỉ mục là một số nguyên và chúng tôi vui mừng lập chỉ mục theo (một ẩn) ROWNUM, tức là không phải là khóa thưa thớt ...

SQL> declare 
    2  type n_array is table of varchar2(30) 
    3   index by binary_integer; 
    4  emp_names n_array; 
    5 begin 
    6  select ename 
    7  bulk collect into emp_names 
    8  from emp ; 
    9 
10  dbms_output.put_line('count='||emp_names.count() 
11        ||'::last='||emp_names.last()); 
12  dbms_output.put_line(emp_names(19)); 
13 
14 end; 
15/
count=19::last=19 
FEUERSTEIN 

PL/SQL procedure successfully completed. 

SQL> 

Để công bằng, nếu bạn cần sử dụng BULK COLLECT, bạn có thể đang xử lý nhiều dữ liệu hơn là thích hợp cho một mảng kết hợp.

Sửa

Một thử nghiệm hiệu suất rẻ-ish của hai phương pháp:

SQL> declare 
    2  type n_array is table of varchar2(30) 
    3   index by binary_integer; 
    4  emp_names n_array; 
    5  s_time pls_integer; 
    6  e_time pls_integer; 
    7 begin 
    8  s_time := dbms_utility.get_time; 
    9  select ename 
10  bulk collect into emp_names 
11  from big_emp 
12  where rownum <= 500; 
13  dbms_output.put_line('bulk collect elapsed time = ' 
14        ||to_char(dbms_utility.get_time - s_time)); 
15  s_time := dbms_utility.get_time; 
16  for r in (select ename, empno from big_emp 
17     where rownum <= 500) 
18  loop 
19   emp_names(r.empno) := r.ename; 
20  end loop; 
21  dbms_output.put_line('sparse array elapsed time = ' 
22        ||to_char(dbms_utility.get_time - s_time)); 
23 end; 
24/

bulk collect elapsed time = 0 
sparse array elapsed time = 0 

PL/SQL procedure successfully completed. 

SQL> 

thử nghiệm hiệu năng tường đồng hồ nổi tiếng là ropey. Nhưng đối với một vài trăm hồ sơ, bất kỳ sự khác biệt nào cũng không đáng để đáng lo ngại, chắc chắn trong bối cảnh sắp xếp nơi mà chúng ta có thể muốn sử dụng một mảng assoociative.

Chỉnh sửa 2

@ Dan nói:

t dường như với tôi rằng muốn truy vấn một phong nha số kích thước của hàng vào một cấu trúc dữ liệu có thể được sử dụng cho constant- tra cứu thời gian phải là một yêu cầu khá phổ biến

Nó thực sự phụ thuộc vào của bạn định nghĩa về "một số có kích thước khá". Có thực sự là nhiều trường hợp mà chúng tôi muốn điền một mảng kết hợp với hàng nghìn hàng, với chỉ mục chuỗi không? Khi chúng tôi nhận được các loại số đó, một bảng cơ sở dữ liệu bình thường có thể hữu ích, đặc biệt là trên 11g Enterprise Edition with resultset caching.

+0

Bao nhiêu? Sự hiểu biết của tôi là ngay cả đối với số lượng hàng tương đối nhỏ (ví dụ, một vài trăm) chi phí của việc chuyển đổi ngữ cảnh SQL sang PL/SQL là đủ để có thể sử dụng BULK COLLECT. Ví dụ đầu tiên của bạn (cho vòng lặp trên một con trỏ) không có vấn đề đó? – Dan

+2

Như FEUERSTEIN tự khuyên, không bao giờ sử dụng con trỏ FOR vòng trừ khi bạn đang đối phó với số lượng nhỏ của hàng (hàng trăm). (Hoặc bạn chỉ đơn giản là không cung cấp cho một damn về hiệu suất) –

+0

Hm. Vậy thì, câu trả lời đúng ở đây là gì? Dường như với tôi rằng muốn truy vấn một số lượng lớn các hàng có kích thước vào một cấu trúc dữ liệu có thể được sử dụng để tra cứu liên tục thời gian phải là một nhu cầu khá phổ biến. – Dan

Các vấn đề liên quan