4

次のようないくつかの更新を含むスクリプトを使用してデータベース(Oracle)を変更しています。

UPDATE customer
SET status = REPLACE(status,   'X_Y',   'xy')
WHERE status LIKE '%X_Y%'
 AND category_id IN
  (SELECT id
   FROM category
   WHERE code = 'ABC');

UPDATE customer
SET status = REPLACE(status,   'X_Z',   'xz')
WHERE status LIKE '%X_Z%'
 AND category_id IN
  (SELECT id
   FROM category
   WHERE code = 'ABC');

-- More updates looking the same...

この場合、DRY(Do n't Repeat Yourself)をどのように実施しますか?

私は特に、次の2つの繰り返し発生する問題を解決することに興味があります。

  • サブクエリを抽出するために、このスクリプトからのみ使用可能な関数を定義しますSELECT id FROM category WHERE code = 'ABC'

  • 一連の置換ルール(一般的なプログラミング言語のように見える可能性があります{"X_Y": "yx", "X_Z": "xz", ...})を作成し、それに対して単一の更新クエリを繰り返します。

ありがとう!

4

8 に答える 8

5

私はそれを単一のクエリに減らします:

UPDATE customer
SET status = REPLACE(REPLACE(status, 'X_Y', 'xy'), 'X_Z', 'xz')
WHERE status REGEXP_LIKE 'X_[YZ]'
 AND category_id IN
  (SELECT id
   FROM category
   WHERE code = 'ABC');
于 2009-03-26T12:42:50.827 に答える
2

私が何かを見逃していない限り、かなり簡単です。

UPDATE customer
SET status = REPLACE(REPLACE(status,'X_Y','xy'),'X_Z','xz')
WHERE ( status LIKE '%X_Y%' Or status LIKE '%X_Z%')
  AND category_id IN
     (SELECT id
      FROM category
      WHERE code = 'ABC');
于 2009-03-26T13:06:49.037 に答える
2

まず第一に、スクリプトはプログラミングと同じものではなく、DRY の原則に従う必要はないことを覚えておいてください。このようなスクリプトは、通常は 1 回限りのものであり、長期間維持されるプログラムではありません。

ただし、PL/SQL を使用してこれを行うことができます。

declare
   type str_tab is table of varchar2(30) index by binary_integer;
   from_tab str_tab;
   to_tab str_tab;
begin
   from_tab(1) := 'X_Y';
   from_tab(2) := 'X_Z';
   to_tab(1) := 'xy';
   to_tab(2) := 'xz';

   for i in 1..from_tab.count loop

      UPDATE customer
      SET status = REPLACE(status,   from_tab(i),   to_tab(i))
      WHERE status LIKE '%' || from_tab(i) || '%'
       AND category_id IN
        (SELECT id
         FROM category
         WHERE code = 'ABC');

   end loop;
end;
于 2009-03-26T12:32:43.330 に答える
1

パラメータを受け取り、それを複数回呼び出すスクリプトを作成します。(スクリプトの実行にSQLPlusを使用していると想定しています。)

replace_in_status.sql:

UPDATE customer
SET status = REPLACE(status,   UPPER('&1'),   '&2')
WHERE status LIKE '%' ||UPPER('&1')|| '%'
 AND category_id IN
  (SELECT id
   FROM category
   WHERE code = 'ABC');

スクリプトの呼び出し:

@replace_in_status X_Y xy
@replace_in_status X_Z xz
于 2009-03-26T12:44:16.657 に答える
1

さて、ここで腰からのショット、私の構文を簡単にしてください:-)

このようなアプローチは役立ちますか:

DECLARE
  v_sql1   VARCHAR2(1000);
  v_sql2   VARCHAR2(2000);
  TYPE T_Rules IS RECORD (srch  VARCHAR2(100),  repl(VARCHAR2(100));
  TYPE T_RuleTab IS TABLE OF T_Rules INDEX BY BINARY_INTEGER;
  v_rules T_RuleTab;

  FUNCTION get_subquery RETURN VARCHAR2 IS
  BEGIN
    RETURN '(SELECT id FROM category WHERE code = ''ABC'')';
  END;

BEGIN
  v_sql1 := 'UPDATE customer SET status = REPLACE('':1'','':2'') WHERE status LIKE ''%:1%'' AND category_id IN ';
  v_rules(1).srch := ('X_Y'); v_rules(1).repl := 'yx';
  v_rules(2).srch := ('X_Z'); v_rules(2).repl := 'xz';

  FOR i IN 1..v_rules.COUNT LOOP
    v_sql2 := v_sql1||get_subquery();
    EXECUTE IMMEDIATE v_sql2 USING v_rules(i).srch, v_rules(i).repl;
  END LOOP;
END;

PL/SQL テーブルを実際のテーブルに置き換えて、その上でカーソルを実行することもできますが、これは 2 番目の要件に対応します。

明らかに、最初の要件である get_subquery にいくつかの作業が残っています ;-)

編集

ダン!WHERE句の置換文字列に注意する必要があることを忘れていました-アンダースコアは、Oracleのワイルドカードに一致する単一の文字です...

于 2009-03-26T15:57:16.837 に答える
0

私はこれに対するいくつかのアプローチを見てきました:

  1. PL/SQLまたはプログラミング言語を使用して動的にSQLをアセンブルするには、文字列バッファを使用します。
  2. XML ファイルに格納されている SQL のフラグメントを再利用および拡張できる IBATIS などのフレームワークを使用します。
  3. ORM フレームワークを使用すると、SQL を直接操作するのではなくオブジェクトを操作することで、この問題を回避できます。

言語と目前の問題によっては、フレームワークを使用し、それを拡張してやりたいことを実行するのが最善の方法かもしれません。

于 2009-03-26T12:36:31.137 に答える
0

スクリプトの重要度に応じて、次のようにします。

  1. コピーして貼り付けて変更するだけ、または
  2. 重複を解決するためのより良い方法がある別のプログラミング言語でスクリプトを作成します。

置換ルールの場合、一時テーブルを作成し、これらの置換ルールを入力してから、このテーブルに結合できます。

サブクエリが常に同じである場合は、最初の問題も結合を使用して解決したことになります。

于 2009-03-26T12:32:37.327 に答える