Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/grails/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL脚本中强制执行DRY(不要重复自己)?_Sql_Oracle_Dry - Fatal编程技术网

如何在SQL脚本中强制执行DRY(不要重复自己)?

如何在SQL脚本中强制执行DRY(不要重复自己)?,sql,oracle,dry,Sql,Oracle,Dry,我正在使用包含以下更新的脚本更改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'

我正在使用包含以下更新的脚本更改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...
在这种情况下,你将如何强制自己不要重复

我对解决以下两个反复出现的问题特别感兴趣:

定义一个函数(仅在此脚本中可用),从类别中提取子查询SELECT id,其中code='ABC'

在流行的编程语言中创建一组类似于{X_Y:yx,X_Z:xz,…}的替换规则,然后在其上迭代单个更新查询


谢谢

根据脚本的重要性,我会:

只需复制、粘贴和修改,或者 用另一种编程语言编写脚本,该语言有更好的方法来解决重复问题。 对于替换规则,您可以创建一个临时表,并用这些替换规则填充它,然后与此表联接


如果子查询总是相同的,那么您也通过使用联接解决了第一个问题。

首先,请记住脚本编写与编程不同,您不必遵循枯燥的原则。像这样的脚本通常是一次性的,而不是需要长时间维护的程序

但您可以使用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;

我已经看到了一些方法:

使用字符串缓冲区使用PL/sql或您的编程语言动态组装sql。 使用诸如IBATIS这样的框架,可以重用和扩展存储在XML文件中的SQL片段。 通过使用对象而不是直接使用SQL,使用ORM框架可以避免这个问题。
根据您的语言和手头的问题,使用框架可能是最好的方法,然后扩展它以完成您希望它完成的任务。

我将把它简化为一个查询:

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');

编写一个包含参数的脚本并多次调用它。我假设您正在使用SQLPlus运行脚本

替换_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

非常简单,除非我遗漏了什么

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');

soulmerge建议的解决方案是最简单的,因此也是最好的——您只需要嵌套要替换的调用。我只想补充一点,条件

status like '%tagada%'
没用。如果未找到搜索的字符串,replace将不会更改任何状态,因此您可以安全地将其应用于所有行。由于搜索字符串丢失在另一个字符串的中间的条件不能使用任何索引,所以作为过滤条件是无用的。 您唯一的筛选条件是类别id上的条件。。。
这就引出了一点,证明了为什么soulmerge的解决方案是最好的:迭代所有更改是一个坏主意。假设category_id上的过滤器具有适度的选择性,Oracle很可能会选择扫描该表。你真的想每次都扫描表格吗?当你可以在一次通过中完成所有更改时?

好的,这里是臀部的一个镜头,请放松我的语法:-

这样的方法是否有帮助:

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表替换为实际表并在其上运行游标,但这满足了您的第二个需求

显然,在get_子查询(您的第一个需求)上还有一些工作要做-

编辑


该死!忘了提到WHERE子句中的替换字符串需要小心-下划线是Oracle中与通配符匹配的单个字符…

脚本和编程之间的界限在哪里?为什么可以在脚本中重复自己,但在程序中却不行?正如我所说的,像这样的脚本通常是一次性的,即在生产中只运行一次,以修复或升级某些数据。一旦运行,它们就被扔掉了,那么谁会关心是否使用了干式原理呢?构成系统永久部分的脚本是另一回事。哦,我设法忽略了像这样的问题。再读一遍你的句子,这很有道理。对不起打扰了-当状态同时为%X_Y%和%X_Z%时,您不处理%X_Z%的子状态。