2017-07-15 170 views
1

我有一個表,列ColA,...,ColE如下。我需要檢查每一條記錄並顯示其在另一現有列NULL值叫做評論打印NULL值列名稱

ColA ColB ColC ColD ColE Comments 
---- ---- ----- ---- ---- ------------------------------ 
1  7  3  4  NULL NULL VALUE In ColE  
2  9  NULL 12  NULL NULL VALUE in ColC, ColE 
3  NULL NULL NULL 10  NULL VALUE IN ColB, Colc, ColD 

輸出應該類似於從上面的結果集Comments列的列名。

+0

什麼是更重要的是你:代碼簡單(便於維修),或效率(執行速度)?不要說**都**!有很多方法可以解決這個問題,但代碼更加麻煩。 – mathguy

+0

請澄清:**現有**欄的意思是什麼,稱爲評論?你的表格(保存在磁盤上)是否有這樣的列?或者你只需​​要在SELECT'查詢的輸出中使用該列? (而不是:列確實存在,你需要'更新'它並將結果保存到磁盤上。) – mathguy

+0

我創建了一個名爲Comments的列 - 如果任何行中有空,並且該列名應該在註釋中更新列爲 - NULL ColE的值....如果更多的列那麼它應該所有那些列 – Puttu

回答

1

這可以使用普通SQL(無過程或函數等)完成,例如使用MERGE語句。一個完整的會話,從設置表格開始,插入值,爲註釋添加一列,然後MERGE聲明,結果「之前」和「之後」顯示如下。

我又添加了一行數據,其中沒有NULL值。你總是需要類似這樣的東西來測試解決方案:當連續有NULL值時,它是否正常工作?

真正的工作是在下面的解決方案中標記爲x的子查詢中完成的。首先我從原始表中獲取數據(加入ROWID,以便稍後可以識別每行)。 UNPIVOT需要Oracle 11.1或更高版本;我也使用LISTAGG,它需要Oracle 11.2或更高版本。你用oracle11goracle10g標記你的帖子,所以我不知道你有什麼,在任何情況下11g等都是營銷名稱;正確的版本是11.1或11.2(或者確實是11.2.0.4.0和類似的)。你可以通過select * from v$version找到你的版本。

如果您沒有Oracle 11.2,則可以使用其他工具(層次查詢或XMLAGG等)來完成字符串聚合 - Stack Overflow中有很多關於如何完成的問題。同樣,如果您沒有Oracle 11.1,則可以使用交叉連接完成未透明處理;我沒有檢查,但我認爲關於堆棧溢出也有很多問題。這兩項行動都是標準的,與您的問題無關;如果您需要幫助,請先搜索此網站,如果遇到困難,請回復。

所以,回到我的方法。我反轉數據,跟蹤rowid。在unpivot操作中,我包含了空值(這不是默認值,因此需要include nulls)。然後從結果中,我只保留值爲NULL的行。然後我按01​​分組,並與LISTAGG聚合。這爲MERGE操作準備子查詢x,該操作在此之外是標準操作。

關於效率的注意事項我問OP中的評論是否應該首選快速執行或解決方案的簡單性(維護更簡單)。 OP表示,易於維護更重要。下面的解決方案更加清晰,但由於以下原因效率不高。在原始表格中,五列中的值已經由它們出現在同一行中的事實「分組」了。不支持丟失這些信息;那麼我們必須再次按ROWID進行分組,以創建LISTAGG字符串併爲MERGE做好準備。GROUP BY操作很昂貴,如果我們編寫的代碼沒有打破輸入行,就不需要了。但是編寫一個不會中斷輸入行的解決方案,雖然可能,但更加複雜,特別是在列數增加的情況下。

SETUP

create table tbl(cola number, colb number, colc number, cold number,cole number); 
insert into tbl(cola, colb, colc, cold, cole) values (1, 7, 3, 4, NULL); 
insert into tbl(cola, colb, colc, cold, cole) values (2, 9, NULL, 12, NULL); 
insert into tbl(cola, colb, colc, cold, cole) values (3, NULL, NULL, NULL, 10); 
insert into tbl(cola, colb, colc, cold, cole) values (0, 1, 2, 3, 5); 
commit; 

alter table tbl add (comment_about_nulls varchar2(1000)); 

select * from tbl; 

COLA COLB COLC COLD COLE COMMENT_ABOUT_NULLS      
---- ---- ---- ---- ---- ---------------------------------------- 
    1 7 3 4            
    2 9  12            
    3     10 
    0 1 2 3 4 

SOLUTION

merge into tbl 
using (
     select rid, listagg(colname, ', ') within group (order by colname) str 
     from  (select rowid as rid, cola, colb, colc, cold, cole from tbl) 
     unpivot include nulls (val for colname in 
          (cola as 'ColA', colb as 'ColB', colc as 'ColC', 
              cold as 'ColD', cole as 'ColE')) 
     where val is null 
     group by rid 
    ) x 
    on (tbl.rowid = x.rid) 
when matched then update 
    set tbl.comment_about_nulls = 'NULL VALUE IN ' || x.str 
; 

select * from tbl; 

COLA COLB COLC COLD COLE COMMENT_ABOUT_NULLS      
---- ---- ---- ---- ---- ---------------------------------------- 
    1 7 3 4  NULL VALUE IN ColE      
    2 9  12  NULL VALUE IN ColC, ColE     
    3     10 NULL VALUE IN ColB, ColC, ColD   
    0 1 2 3 5 
+0

謝謝我的同事(數學家),我欣賞你的解決方案。 –

+0

@mathguy - 非常感謝,它按照我的要求工作。感謝你的時間和幫助 – Puttu

0

是你想要的代碼嗎?

declare 
    v_table_name varchar2(31) := 'MYTABLE'; 
    v_sql   varchar2(4000); 
    v_columnName varchar2(100); 
    v_col   pls_integer; 
    cm   varchar2(1); 
    i    pls_integer := 0; 
begin 
for b in (select rownum rnum, t.rowid rid, t.* from mytable t order by rownum) 
loop 
begin 
for c in (select t.* from user_tab_columns t where t.table_name = v_table_name order by column_name) 
loop  
    v_sql := 'select ' || c.column_name || ' from ' || v_table_name || ' t where t.rowid = '''||b.rid||''''; 
    execute immediate v_sql into v_col; 
    if nvl(v_col,0)=0 then  
    if i>0 then cm:=','; end if; 
    v_columnName := v_columnName||cm||c.column_name; 
    i:=+1; 
    end if; 
end loop; 
    dbms_output.put_line(rpad(nvl(to_char(b.rnum),'NULL'),5,' ')||' '||rpad(nvl(to_char(b.cola),'NULL'),5,' ')||' '||rpad(nvl(to_char(b.colb),'NULL'),5,' ')||' '||rpad(nvl(to_char(b.colc),'NULL'),5,' ')||' '||rpad(nvl(to_char(b.cold),'NULL'),5,' ')||' '||rpad(nvl(to_char(b.cole),'NULL'),5,' ')||' '||'NULL VALUE In '||v_columnName); 
    v_columnName := null; i := 0; cm := null; 
    exception when no_data_found then continue; 
end; 
end loop; 
end; 

通過考慮colA-E作爲數字類型和註釋在mytable中是不存在的。

+0

ColA ColB ColC ColD ColE ---- ---- ----- ---- ---- 1 7 3 4 NULL 2 9 NULL NULL 12 3 NULL NULL NULL 10 我的結果應該是這樣的,請不列包含兩個號碼和VARCHAR值 結果 NULL VALUE在COLE 0123中ColC中的NULL值,ColE ColB,Colc,ColD中的NULL值 – Puttu

+0

感謝您的迴應。以下是我期待的輸出結果 ColA ColB ColC ColD ColE ---- ---- ----- ---- ---- 1 7 3 4 NULL 2 9 NULL 12 NULL 3 NULL NULL NULL 10 我的結果應該是這樣的,請不列同時包含數字和VARCHAR值 結果 NULL值在COLC,科爾 空值IN COLB,COLC,冷 – Puttu

+0

科爾 NULL值部分「...」NULL VALUE在'|| v_columnName「中已經代表了這個(註釋)。你真的試過了代碼嗎?只是,我沒有爲標題部分提供任何代碼。 –