2014-02-26 50 views
0

首先,我對Oracle PLSQL非常生疏,而且我看到有幾個人說這不可能完成,其他人說可以,我只是無法做到這一點。任何幫助將不勝感激。PLSQL動態獲取記錄中的屬性值?

我想讀動態記錄類型的列的值。

我有一個帶有標記的消息,我需要用記錄集中的值替換標記。

因此,該消息是這樣的:[狀態]由[AGENT_NAME]

我有我在哪裏解析出令牌另一個地方。

在Java腳本,我知道這可以實現:(將在控制檯上運行)

var record = { 
    status : "Open", 
    agent_name : "John" 
}; 

var record2 = { 
    status : "Close", 
    agent_name : "Joe" 
}; 
var records = [record, record2]; 

var token1 = "status"; 
var token2 = "agent_name"; 



for(var i=0; i<records.length; i++){ 
    console.log(records[i][token1] + " by " + records[i][token2]); 
} 


Results : Open by John 
      Close by Joe 

我想做同樣的事情在PLSQL

這裏是我的測試PLSQL:

SET SERVEROUTPUT ON; 
declare 

    TYPE my_record is RECORD 
    (
     status   VARCHAR2(30), 
     agent_name  varchar2(30) 
    ); 

    TYPE my_record_array IS VARRAY(6) OF my_record; 
    v_records   my_record_array := my_record_array(); 
    v_current_rec  my_record; 
    v_current_rec2  my_record; 
    v_token    varchar2(50):= 'agent_name'; 
    v_token2    varchar2(50):= 'status'; 

begin 

    v_current_rec.status := 'Open'; 
    v_current_rec.agent_name := 'John'; 
    v_records.extend; 
    v_records(1) := v_current_rec; 

    v_current_rec2.status := 'Close'; 
    v_current_rec2.agent_name := 'Ron'; 
    v_records.extend; 
    v_records(2) := v_current_rec2; 

    FOR i IN 1..v_records.COUNT LOOP 
     --Hard coded 
     DBMS_OUTPUT.PUT_LINE(v_records(i).status || ' by ' || v_records(i).agent_name); 

     --Substitution vars entering v_records(i).status and v_records(i).agent_name for the prompts. 
     --How to do this without user interaction. 
     DBMS_OUTPUT.PUT_LINE(&status || ' by ' || &agent_name); 

     --Dynamically that doesn't work. How would this be accomplished 
     DBMS_OUTPUT.PUT_LINE(v_records(i).v_token || ' by ' || v_records(i).v_token2); 
    END LOOP; 
END; 

我嘗試使用替代變量,如果我使用,將工作:

DBMS_ OUTPUT.PUT_LINE(& agent_name)並在出現提示時輸入v_records(i).agent_name。我如何在飛行中完成此操作?

答:

set serveroutput on; 
DECLARE 
type sr_record_map 
IS 
    TABLE OF VARCHAR2(30) INDEX BY VARCHAR2(30); 


type record_set 
is 
TABLE of sr_record_map index by BINARY_INTEGER; 

    v_current_rec    sr_record_map; 
    v_record_set    record_set; 
    v_token     varchar2(30) := 'status'; 
    v_token2     varchar2(30) := 'agent_name'; 

    v_index     number :=1; 

begin 
v_current_rec('status') := 'Open'; 
v_current_rec('agent_name') := 'John'; 
v_record_set(1) := v_current_rec; 

v_current_rec('status') := 'Close'; 
v_current_rec('agent_name') := 'Joe'; 
v_record_set(2) := v_current_rec; 

FOR i in 1..v_record_set.COUNT LOOP 
    v_current_rec := v_record_set(i); 
    DBMS_OUTPUT.PUT_LINE(v_current_rec(v_token) || ' by ' || v_current_rec(v_token2)); 
END LOOP; 
end; 
+0

你說,你的記錄可能有任何成員(列),你想通過選擇一個打印它們? –

+0

我有多個消息,可能有任何數量的令牌。我知道這些字段存在於記錄中。因此,如果我有令牌代理名稱,我想要評估字符串v_records(i).agent_name並從記錄中獲取值。所以我可以用值替換消息中的令牌。 – John

回答

2

使用的ASSOCIATIVE ARRAY就像地圖在Java中

DECLARE 
type my_record_map 
IS 
    TABLE OF VARCHAR2(30) INDEX BY VARCHAR2(30); 
type my_record 
IS 
    record 
    (
    my_members my_record_map); 
type final_map 
IS 
    TABLE OF my_record INDEX BY VARCHAR2(20); 
    v_final_map final_map; 
    v_my_record_map my_record_map; 
    v_my_record my_record; 
    index_name VARCHAR2(100); 
    index_name_record VARCHAR2(100); 
BEGIN 
    /* Individual Records as key value pairs with their Corresponding Columns */ 
    /* You can put any member name inside */ 

    v_my_record_map('status')  := 'Open'; 
    v_my_record_map('agent_name') := 'John'; 
    v_my_record_map('added_by') := 'Maheshwaran'; 


    /* Put it as a record */ 
    v_my_record.my_members := v_my_record_map; 

    /* Put the record inside Another Map with any Key */ 
    v_final_map('Record1')  := v_my_record; 


    v_my_record_map('status')  := 'Close'; 
    v_my_record_map('agent_name') := 'Joe'; 
    v_my_record_map('added_by') := 'Ravisankar'; 

    v_my_record.my_members := v_my_record_map; 

    v_final_map('Record2')  := v_my_record; 

    /* Take the First Key in the Outer most Map */ 
    index_name   := v_final_map.FIRST; 
    LOOP 
    /* status Here can be dynamic */ 
    DBMS_OUTPUT.PUT_LINE(CHR(10)||'######'||v_final_map(index_name).my_members('status') ||' by '||v_final_map(index_name).my_members('agent_name')||'######'||CHR(10)); 

    index_name_record := v_final_map(index_name).my_members.FIRST; 
    DBMS_OUTPUT.PUT_LINE('$ Ávailable Other Members + Values.. $'||CHR(10)); 
    LOOP 
     DBMS_OUTPUT.PUT_LINE('  '||index_name_record ||'='||v_final_map(index_name).my_members(index_name_record)); 
     index_name_record := v_final_map(index_name).my_members.NEXT(index_name_record); 
     EXIT WHEN index_name_record IS NULL; 
    END LOOP; 
    /* Next gives you the next key */ 
    index_name := v_final_map.NEXT(index_name); 
    EXIT WHEN index_name IS NULL; 
    END LOOP; 
END; 
/

OUTPUT:

######Open by John###### 

$ Ávailable Other Members + Values.. $ 

    added_by=Maheshwaran 
    agent_name=John 
    status=Open 

######Close by Joe###### 

$ Ávailable Other Members + Values.. $ 

    added_by=Ravisankar 
    agent_name=Joe 
    status=Close 
+0

就是這樣。將在這個例子的問題中發佈答案。 – John

0

我不認爲它可以與一個記錄類型來完成。對象類型可能是可能的,因爲您可以從數據字典中查詢字段,但通常沒有可用的地方(儘管有一個名爲PL/Scope的11g設施,如果啓用它可能會允許)。

由於您在使用記錄類型的同一地方定義了記錄類型,並且如果您擁有可管理的字段數,可能會更簡單,只需要替換每個標記(只是(!))浪費如果在消息中不存在CPU的位,則需要一點CPU:

declare 

    TYPE my_record is RECORD 
    (
     status   VARCHAR2(30), 
     agent_name  varchar2(30) 
    ); 

    TYPE my_record_array IS VARRAY(6) OF my_record; 
    v_records   my_record_array := my_record_array(); 
    v_current_rec  my_record; 
    v_current_rec2  my_record; 
    v_message   varchar2(50):= '[status] by [agent_name]'; 
    v_result    varchar2(50); 
begin 

    v_current_rec.status := 'Open'; 
    v_current_rec.agent_name := 'John'; 
    v_records.extend; 
    v_records(1) := v_current_rec; 

    v_current_rec2.status := 'Close'; 
    v_current_rec2.agent_name := 'Ron'; 
    v_records.extend; 
    v_records(2) := v_current_rec2; 

    FOR i IN 1..v_records.COUNT LOOP 
     v_result := v_message; 
     v_result := replace(v_result, '[agent_name]', v_records(i).agent_name); 
     v_result := replace(v_result, '[status]', v_records(i).status); 
     DBMS_OUTPUT.PUT_LINE(v_result);  
    END LOOP; 
END; 
/

anonymous block completed 
Open by John 
Close by Ron 

它當然需要維護;如果將字段添加到記錄類型中,則需要將相匹配的replace添加到正文中。

我假設在現實世界中,帶有標記的消息文本將被傳遞給一個過程。我不確定這是值得解析出令牌的,除非你需要它們來做別的事情。

+0

我們想出了類似的東西,但基本上試圖使它成爲動態的,以便我們可以將數據添加到我們發送到過程中的記錄中,然後將新令牌插入消息中。這個過程會得到一個記錄集和一條消息。創建一個「自動」映射到記錄中的列。 – John

+0

@John - 只要記錄中的每個字段都有一個「替換」,我不清楚是什麼讓它動態化。除非在記錄中定義字段,否則不能向消息添加新的標記?也許你根本不需要一個記錄集合,但如果這些字段需要在運行時更改,那麼它是一個關聯數組? –

+0

這只是原型。 Type實際上是在其他地方定義的。我正在儘量減少變化的要點。我們有幾個proc將把記錄集發送到這個proc。每當其他過程發生變化時,我都想阻止必須改變它。 – John

0

舉個例子,我附上簡單的代碼,通過它可以動態地比較中的任意兩項紀錄通過表名和ID值的任何表,以獲得數據的差異..

DECLARE 

p_id_1 NUMBER DEFAULT 697403; 
p_id_2 NUMBER DEFAULT 697402; 
p_table_name VARCHAR2(200) DEFAULT 'Name of the table'; 
V_result_1 VARCHAR2(2000); 
V_result_2 VARCHAR2(2000); 

CURSOR cur IS 
SELECT * FROM ALL_TAB_COLUMNS WHERE table_name = p_table_name ; 

BEGIN 

FOR rec IN cur LOOP 

EXECUTE IMMEDIATE 
     'SELECT ' || rec.COLUMN_NAME || ' FROM ' || P_TABLE_NAME || 
     ' WHERE ID = :1 ' 
     INTO V_result_1 
     USING P_ID_1 
     ; 

EXECUTE IMMEDIATE 
     'SELECT ' || rec.COLUMN_NAME || ' FROM ' || P_TABLE_NAME || 
     ' WHERE ID = :1 ' 
     INTO V_result_2 
     USING P_ID_2 
     ; 

IF NVL(v_result_1, 0) <> NVL(v_result_2,0) THEN 
DBMS_OUTPUT.PUT_LINE('Column_name ' || rec.column_name || ' ' || v_result_1 || '\' || v_result_2); 
END IF; 

END LOOP; 

END;