web-dev-qa-db-ja.com

CASEおよびINを使用した更新-Oracle

SQL Serverの魅力のように機能するクエリを作成しました。残念ながら、Oracleデータベースで実行する必要があります。私はそれを変換する方法についての解決策を求めてウェブを徹底的に探してきましたが、成功しませんでした:/

クエリはi SQLのようになります。

UPDATE tab1   SET budgpost_gr1=     
CASE  WHEN (budgpost in (1001,1012,50055))  THEN 'BP_GR_A'   
      WHEN (budgpost in (5,10,98,0))  THEN 'BP_GR_B'  
      WHEN (budgpost in (11,876,7976,67465))     
      ELSE 'Missing' END`

私の問題は、列budgetpost_gr1およびbudgetpostは英数字であり、Oracleはリストを数字として表示したいようです。リストは、コンマ区切りリストとして事前定義された変数/パラメーターであり、クエリにダンプされるだけです。

23
user641605

実行するソリューションを手に入れました。それが最適であるかどうかわからない。私がやることは、 http://blogs.Oracle.com/aramamoo/2010/05/how_to_split_comma_separated_string_and_pass_to_in_clause_of_select_statement.html に従って文字列を分割することです

を使用して:
select regexp_substr(' 1, 2 , 3 ','[^,]+', 1, level) from dual
connect by regexp_substr('1 , 2 , 3 ', '[^,]+', 1, level) is not null;

したがって、最終的なコードは次のようになります($bp_gr1'1,2,3のような文字列です):

UPDATE TAB1
SET    BUDGPOST_GR1 =
          CASE
             WHEN ( BUDGPOST IN (SELECT     REGEXP_SUBSTR ( '$BP_GR1',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                 FROM       DUAL
                                 CONNECT BY REGEXP_SUBSTR ( '$BP_GR1',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                               IS NOT NULL) )
             THEN
                'BP_GR1'
             WHEN ( BUDGPOST IN (SELECT     REGEXP_SUBSTR ( ' $BP_GR2',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                 FROM       DUAL
                                 CONNECT BY REGEXP_SUBSTR ( '$BP_GR2',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                               IS NOT NULL) )
             THEN
                'BP_GR2'
             WHEN ( BUDGPOST IN (SELECT     REGEXP_SUBSTR ( ' $BP_GR3',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                 FROM       DUAL
                                 CONNECT BY REGEXP_SUBSTR ( '$BP_GR3',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                               IS NOT NULL) )
             THEN
                'BP_GR3'
             WHEN ( BUDGPOST IN (SELECT     REGEXP_SUBSTR ( '$BP_GR4',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                 FROM       DUAL
                                 CONNECT BY REGEXP_SUBSTR ( '$BP_GR4',
                                                            '[^,]+',
                                                            1,
                                                            LEVEL )
                                               IS NOT NULL) )
             THEN
                'BP_GR4'
             ELSE
                'SAKNAR BUDGETGRUPP'
          END;

より高速に実行する方法はありますか?

1
user641605

Budgetpostは英数字であると言いました。つまり、文字列との比較を探しています。パラメータを一重引用符で囲むようにしてください(Case式に最後のTHENがありません)。

UPDATE tab1   
SET budgpost_gr1=   CASE  
                        WHEN (budgpost in ('1001','1012','50055'))  THEN 'BP_GR_A'   
                        WHEN (budgpost in ('5','10','98','0'))  THEN 'BP_GR_B'  
                        WHEN (budgpost in ('11','876','7976','67465')) THEN 'What?'
                        ELSE 'Missing' 
                        END 
33
Thomas

to_numberを使用して、budgpostを数値に変換します。

when to_number(budgpost,99999) in (1001,1012,50055) THEN 'BP_GR_A' 

編集:9に十分な数のto_numberがあり、最大の予算投稿に一致することを確認してください。

数値以外の予算投稿がある場合、クエリの最後にwhere句を使用してそれらを除外できます。

where regexp_like(budgpost, '^-?[[:digit:],.]+$')
1
Andomar

「リストは、コンマ区切りリストとして事前定義された変数/パラメーターです」。あなたのクエリは実際には

UPDATE tab1   SET budgpost_gr1=     
CASE  WHEN (budgpost in ('1001,1012,50055'))  THEN 'BP_GR_A'   
      WHEN (budgpost in ('5,10,98,0'))  THEN 'BP_GR_B'  
      WHEN (budgpost in ('11,876,7976,67465'))     
      ELSE 'Missing' END`

その場合、文字列を取得してそれを数値のリストに解析する関数が必要です。

create type tab_num is table of number;

create or replace function f_str_to_nums (i_str in varchar2) return tab_num is
  v_tab_num tab_num := tab_num();
  v_start   number := 1;
  v_end     number;
  v_delim   VARCHAR2(1) := ',';
  v_cnt     number(1) := 1;
begin
  v_end := instr(i_str||v_delim,v_delim,1, v_start);
  WHILE v_end > 0 LOOP
    v_cnt := v_cnt + 1;
    v_tab_num.extend;
    v_tab_num(v_tab_num.count) := 
                  substr(i_str,v_start,v_end-v_start);
    v_start := v_end + 1;
    v_end := instr(i_str||v_delim,v_delim,v_start);
  END LOOP;
  RETURN v_tab_num;
end;
/

その後、次のような関数を使用できます。

select column_id, 
   case when column_id in 
     (select column_value from table(f_str_to_nums('1,2,3,4'))) then 'red' 
   else 'blue' end
from  user_tab_columns
where table_name = 'EMP'
1
Gary Myers

結合を使用して更新するために使用できる別の回避策があります。以下のこの例では、ルックアップ値を含めることでテーブルを非正規化することを前提としています(この場合、ユーザー名をテーブルに保存します)。更新には、名前を見つけるための結合が含まれており、出力は、検出される名前または検出されない名前をサポートするCASEステートメントで評価されます。この作業を行うための鍵は、結合から出てくるすべての列が一意の名前を持つようにすることです。サンプルコードで、b.user_nameがa.user_name列と競合し、一意の名前「user_user_name」でエイリアス化する必要があることに注意してください。

UPDATE
(
    SELECT a.user_id, a.user_name, b.user_name as user_user_name
    FROM some_table a
    LEFT OUTER JOIN user_table b ON a.user_id = b.user_id
    WHERE a.user_id IS NOT NULL
)
SET user_name = CASE
    WHEN user_user_name IS NOT NULL THEN user_user_name
    ELSE 'UNKNOWN'
    END;   
0
Scott