2012-04-25 41 views
8

Tôi có một bảng có tên là Table1. Nó có rất nhiều cột, một trong số đó là Column1. Tôi không biết các cột khác, chúng thậm chí có thể thay đổi đôi khi. Có một kiểu con trỏ kiểu gõ mạnh mẽ trả về Table1% rowtype, có tên là cur_Table1. Tôi có một thủ tục được lưu trữ có tên là SP1 có tham số out of type cur_Table1. Tôi đang gọi thủ tục được lưu trữ SP1 này từ một cơ sở dữ liệu khác mà chỉ thấy thủ tục được lưu trữ này, nhưng không phải là bảng hoặc chính loại đó. Làm thế nào để tôi chỉ chọn Column1 từ con trỏ trả về? Tôi biết tôi có thể lấy vào một bản ghi hoặc nhiều biến vì con trỏ có các cột, nhưng tôi chỉ biết sự tồn tại của một cột vì vậy tôi không thể khai báo toàn bộ bản ghi hoặc số biến chính xác.Oracle - chọn một cột cụ thể từ con trỏ ref

+0

Vui lòng giải thích cách bạn đề xuất gọi thủ tục trong cơ sở dữ liệu khác (hoặc bất kỳ cơ sở dữ liệu nào), mà không thể xem các loại đối số. –

+0

Tôi đã thực hiện "cấp quyền thực thi trên SP cho người khác", nhưng không cấp bất cứ điều gì khác, không phải trên bảng hoặc gói loại. Và nó hoạt động. – fejesjoco

+0

Ồ, và ở phía gọi, tôi đưa ra tham số của SP vào một sys_refcursor, tất nhiên. – fejesjoco

Trả lời

6

Bạn có thể làm điều này với DBMS_SQL, nhưng không đẹp.

Bảng và mẫu dữ liệu (COLUMN1 có các số từ 1 - 10):

create table table1(column1 number, column2 date, column3 varchar2(1000), column4 clob); 

insert into table1 
select level, sysdate, level, level from dual connect by level <= 10; 
commit; 

trọn gói với một thủ tục mở ra một con trỏ ref và chọn tất cả mọi thứ:

create or replace package test_pkg is 
    type cur_Table1 is ref cursor return table1%rowtype; 
    procedure sp1(p_cursor in out cur_table1); 
end; 
/

create or replace package body test_pkg is 
    procedure sp1(p_cursor in out cur_table1) is 
    begin 
     open p_cursor for select column1, column2, column3, column4 from table1; 
    end; 
end; 
/

Khối PL/SQL đọc dữ liệu COLUMN1 từ con trỏ ref:

--Basic steps are: call procedure, convert cursor, describe and find columns, 
--then fetch rows and retrieve column values. 
-- 
--Each possible data type for COLUMN1 needs to be added here. 
--Currently only NUMBER is supported. 
declare 
    v_cursor sys_refcursor; 
    v_cursor_number number; 

    v_columns number; 
    v_desc_tab dbms_sql.desc_tab; 
    v_position number; 
    v_typecode number; 
    v_number_value number; 
begin 
    --Call procedure to open cursor 
    test_pkg.sp1(v_cursor); 
    --Convert cursor to DBMS_SQL cursor 
    v_cursor_number := dbms_sql.to_cursor_number(rc => v_cursor); 
    --Get information on the columns 
    dbms_sql.describe_columns(v_cursor_number, v_columns, v_desc_tab); 

    --Loop through all the columns, find COLUMN1 position and type 
    for i in 1 .. v_desc_tab.count loop 
     if v_desc_tab(i).col_name = 'COLUMN1' then 
      v_position := i; 
      v_typecode := v_desc_tab(i).col_type; 

      --Pick COLUMN1 to be selected. 
      if v_typecode = dbms_types.typecode_number then 
       dbms_sql.define_column(v_cursor_number, i, v_number_value); 
      --...repeat for every possible type. 
      end if; 
     end if; 
    end loop; 

    --Fetch all the rows, then get the relevant column value and print it 
    while dbms_sql.fetch_rows(v_cursor_number) > 0 loop 
     if v_typecode = dbms_types.typecode_number then 
      dbms_sql.column_value(v_cursor_number, v_position, v_number_value); 
      dbms_output.put_line('Value: '||v_number_value); 
     --...repeat for every possible type 
     end if; 
    end loop; 
end; 
/
--Basic steps are: call procedure, convert cursor, describe and find columns, 
--then fetch rows and retrieve column values. 
-- 
--Each possible data type for COLUMN1 needs to be added here. 
--Currently only NUMBER is supported. 
declare 
    v_cursor sys_refcursor; 
    v_cursor_number number; 

    v_columns number; 
    v_desc_tab dbms_sql.desc_tab; 
    v_position number; 
    v_typecode number; 
    v_number_value number; 
begin 
    --Call procedure to open cursor 
    test_pkg.sp1(v_cursor); 
    --Convert cursor to DBMS_SQL cursor 
    v_cursor_number := dbms_sql.to_cursor_number(rc => v_cursor); 
    --Get information on the columns 
    dbms_sql.describe_columns(v_cursor_number, v_columns, v_desc_tab); 

    --Loop through all the columns, find COLUMN1 position and type 
    for i in 1 .. v_desc_tab.count loop 
     if v_desc_tab(i).col_name = 'COLUMN1' then 
      v_position := i; 
      v_typecode := v_desc_tab(i).col_type; 

      --Pick COLUMN1 to be selected. 
      if v_typecode = dbms_types.typecode_number then 
       dbms_sql.define_column(v_cursor_number, i, v_number_value); 
      --...repeat for every possible type. 
      end if; 
     end if; 
    end loop; 

    --Fetch all the rows, then get the relevant column value and print it 
    while dbms_sql.fetch_rows(v_cursor_number) > 0 loop 
     if v_typecode = dbms_types.typecode_number then 
      dbms_sql.column_value(v_cursor_number, v_position, v_number_value); 
      dbms_output.put_line('Value: '||v_number_value); 
     --...repeat for every possible type 
     end if; 
    end loop; 
end; 
/
+7

Wow ... và tôi nghĩ rằng nó sẽ là một cái gì đó tầm thường như "chọn column1 từ con trỏ". – fejesjoco

1

Không biết nếu đó là một lựa chọn hay không, nhưng sẽ không phải là giải pháp tốt hơn để tạo ra một hàm trả về giá trị cụ thể mà bạn đang tìm kiếm? Điều đó tránh được phí tổn gửi dữ liệu bổ sung. Ngoài ra, bạn có thể xác định một con trỏ với một tập hợp các trường đã biết trong đó cả hai bên đều biết.

+0

Tôi không có quyền kiểm soát cơ sở dữ liệu của SP, tôi chỉ cần gọi nó từ một nơi khác với tư cách là khách hàng của bên thứ 3. – fejesjoco

3

Với câu hỏi ban đầu, câu trả lời của jonearles vẫn đúng, vì vậy tôi sẽ để nó được đánh dấu như vậy, nhưng cuối cùng tôi đã làm điều gì đó hoàn toàn khác và tốt hơn nhiều.

Vấn đề là/là tôi không có quyền kiểm soát cơ sở dữ liệu của SP1, tôi chỉ cần gọi nó từ nơi khác với tư cách là khách hàng của bên thứ ba. Bây giờ tôi quản lý để có được sự cho phép để xem không chỉ SP, mà còn là loại con trỏ. Tôi vẫn không xem bảng nhưng bây giờ có một giải pháp sạch hơn nhiều:

Trong cơ sở dữ liệu khác mà tôi đã được cấp quyền truy cập để xem loại này bây giờ:

type cur_Table1 is ref cursor return Table1%rowtype; 

Vì vậy, trong cơ sở dữ liệu của tôi, tôi có thể làm hiện tại:

mycursor OtherDB.cur_Table1; 
myrecord mycursor%rowtype; 
... 
OtherDB.SP1(mycursor); 
fetch mycursor into myrecord; 
dbms_output.put_line(myrecord.Column1); 

Xem, tôi vẫn không cần bất kỳ quyền truy cập nào vào bảng, tôi chỉ thấy con trỏ. Điều quan trọng là phép thuật% rowtype cũng hoạt động cho con trỏ, không chỉ các bảng. Nó không hoạt động trên sys_refcursor, nhưng nó thực hiện trên một kiểu gõ mạnh mẽ. Với mã này, tôi không phải quan tâm nếu có bất cứ điều gì thay đổi ở phía bên kia, tôi không phải xác định tất cả các cột hoặc bản ghi, tôi chỉ cần chỉ định một cột mà tôi quan tâm.

Tôi thực sự yêu thái độ OOP này về Oracle.

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