动态UPDATE语句,用于更新上一个SELECT返回的列中的值

时间:2015-09-28 15:21:35

标签: sql oracle hsqldb

从本质上讲,我想做的是:

  • 查找与特定查询匹配的所有表格及其列
  • 更新这些列中的值。

所以说我有类似

的东西
SELECT COLUMN_NAME, TABLE_NAME, TABLE_SCHEMA
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE
    (
      TABLE_SCHEMA = 'PUBLIC'
    ) AND (
      COLUMN_NAME LIKE '%SOMETHING%'
      OR COLUMN_NAME LIKE '%SOMETHINGELSE%'
    ) AND (
      DATA_TYPE = 'BIGINT' OR
      DATA_TYPE = 'TINYINT' OR
      DATA_TYPE = 'SMALLINT' OR
      DATA_TYPE = 'INTEGER'
    )

或者对于Oracle来说:

SELECT COLUMN_NAME, TABLE_NAME
  FROM USER_TAB_COLS
  WHERE
    (
      COLUMN_NAME LIKE '%SOMETHING%'
      OR COLUMN_NAME LIKE '%SOMETHINGELSE%'
    ) AND
    DATA_TYPE IN ('NUMBER')

我想在所有结果列上执行UPDATE,类似于:

UPDATE _RESULTING_COLUMN_NAMES_HERE_THEORETICALLY_
  SET
    _SINGLE_COLUMN_NAME_ = _SOME_NEW_VALUE_
  WHERE _SINGLE_COLUMN_NAME_ = _SOME_OLD_VALUE_;

很明显,这不起作用甚至不存在,但我希望你明白我想要达到的目标。

我可以看到为UPDATE结果集中的每个匹配表生成SELECT语句的方法,但我真的没有看到如何实现这一点。

为了让事情变得更有趣,我需要为old_value到new_value转换列表这样做。

欢迎任何想法。

我正在尝试将HSQLDB和Oracle作为我的2项要求,但支持其他平台将是一个相当不错的奖励。

2 个答案:

答案 0 :(得分:1)

只要您认为需要使用动态SQL,就应该停下来,退后一步,看看是否有其他方法可以做到这一点,或者您是否真的需要做什么你在做什么。

我可能会严重质疑你的基础"要求"的:

  • 更新匹配某些字符串的所有表的所有列,以及整数(或其变体)类型的所有列。

有些东西仍然闻起来有趣"有趣" ...我非常小心你正在做什么 - 确保你知道结果会是什么,测试测试...再次测试......在某个DEV盒子上...

说,无论何时我需要求助于动态SQL,我发现最简单的方法是从"模板"开始:

所以在你的情况下,你想要触发的最终更新是你所说的:

  UPDATE _RESULTING_COLUMN_NAMES_HERE_THEORETICALLY_
    SET
      _SINGLE_COLUMN_NAME_ = _SOME_NEW_VALUE_
    WHERE _SINGLE_COLUMN_NAME_ = _SOME_OLD_VALUE_;

好的,我现在可能会将其重新编写为字符串,并使用WITH子句启动查询:

  WITH w_template AS ( select 
        rtrim(q'[ UPDATE _RESULTING_COLUMN_NAMES_HERE_THEORETICALLY_    ]')||CHR(10)||
        rtrim(q'[   SET                                                 ]')||CHR(10)||
        rtrim(q'[     _SINGLE_COLUMN_NAME_ = _SOME_NEW_VALUE_           ]')||CHR(10)||
        rtrim(q'[   WHERE _SINGLE_COLUMN_NAME_ = _SOME_OLD_VALUE_;      ]')
           template from dual
        )

注意我还没有改变你的查询中的任何内容。我所做的只是将"q'[""]'"包围起来...... rtrimCHR(10)并将其放在WITH子句中。

1)q'[ some string ]'是另一种做字符串的方法。它的优点是你可以在该字符串中使用单引号而没有任何实际问题: 即q'[ some 'string' ]'工作得很好......打印" some 'string' "

2)RTRIM - 我在那里留下了作为装饰品的行尾的空格,以便我们更容易阅读。但是,由于字符串的长度限制,这些空间可以增长,字符串非常大,非常快,查询量更大。所以RTRIM是我养成的习惯。保留化妆品空间,但告诉Oracle不要使用它们;)它们只适合我们。

3)CHR(10) - 仅限化妆品 - 如果您愿意,可以将其关闭。我喜欢它,就像你想在测试期间转储查询一样,你可以轻松阅读查询并查看它的内容。

接下来我们将更改动态值的名称,以便我们更轻松地发现它们并替换它们:

  WITH w_template AS ( select 
        rtrim(q'[ UPDATE <table_name>                   ]')||CHR(10)||
        rtrim(q'[   SET                                 ]')||CHR(10)||
        rtrim(q'[     <col_name> = <col_new_val>        ]')||CHR(10)||
        rtrim(q'[   WHERE <col_name> = <col_old_val>;   ]')
           template from dual
        )

我所做的就是创建一个易于识别的&#34;字符串&#34;我将在以后用它替换值。

注意如果您的列是字符串,则可能需要引号:<col_name> = '<col_new_val>' 但似乎你正在处理整数数据..所以我认为我们还好......

现在我们需要提取您的数据......所以我们回到您的原始查询:

        SELECT COLUMN_NAME, TABLE_NAME
          FROM USER_TAB_COLS
          WHERE
            (
              COLUMN_NAME LIKE '%SOMETHING%'
              OR COLUMN_NAME LIKE '%SOMETHINGELSE%'
            ) AND
            DATA_TYPE IN ('NUMBER')

嗯,我在那里的查询中必须相信你,我不确定它会在Oracle上运行,但你比我更了解你的查询;)所以我&#39 ; ll相信你的查询&#34;原样&#34;对于这个例子 - 只要它选择你想要的数据,并包括你想要的表名,列名和前/后值(它目前没有),我们就可以了。< / p>

所以我们需要做的就是将这两者结合起来......我们会这样做:

  WITH w_template AS ( select 
        rtrim(q'[ UPDATE <table_name>                   ]')||CHR(10)||
        rtrim(q'[   SET                                 ]')||CHR(10)||
        rtrim(q'[     <col_name> = <col_new_val>        ]')||CHR(10)||
        rtrim(q'[   WHERE <col_name> = <col_old_val>;   ]')
           template from dual
        )
     w_data AS (
        SELECT COLUMN_NAME, TABLE_NAME
          FROM USER_TAB_COLS
          WHERE
            (
              COLUMN_NAME LIKE '%SOMETHING%'
              OR COLUMN_NAME LIKE '%SOMETHINGELSE%'
            ) AND
            DATA_TYPE IN ('NUMBER')
        )

然后我们只需添加最终查询,使用REPLACE替换值..

(注意:不知道你得到了什么&#34; some_new_value&#34;以及&#34; some_old_value&#34;来自???你必须将它加入你的查询..)

  WITH w_template AS ( select 
        rtrim(q'[ UPDATE <table_name>                   ]')||CHR(10)||
        rtrim(q'[   SET                                 ]')||CHR(10)||
        rtrim(q'[     <col_name> = <col_new_val>        ]')||CHR(10)||
        rtrim(q'[   WHERE <col_name> = <col_old_val>;   ]')
           template from dual
        ),
     w_data AS (
        SELECT COLUMN_NAME, TABLE_NAME
          FROM USER_TAB_COLS
          WHERE
            (
              COLUMN_NAME LIKE '%SOMETHING%'
              OR COLUMN_NAME LIKE '%SOMETHINGELSE%'
            ) AND
            DATA_TYPE IN ('NUMBER')
        )
  SELECT REPLACE ( REPLACE ( REPLACE ( REPLACE ( 
              wt.template, '<table_name>', 
                             wd.table_name ),
                 '<col_name>', wd.column_name ),
                 '<col_new_val>', ??? ),
                 '<col_old_val>', ??? )  query
    FROM w_template wt,
         w_data wd
我离开了?那里有旧的/新的价值观,因为你没有说明他们来自哪里? 但如果你运行它,应该吐出一些更新语句..;)

一旦你对这些感到满意,推动他们立即执行是一件容易的事。

同样,我建议对这种方法保持谨慎,这对于1次迁移是可以的,或者这样,但是,不建议每天定期运行。 ;)

答案 1 :(得分:0)

  

查找与特定查询匹配的所有表及其列,     更新这些列中的值。

使用HSQLDB时,不可能仅使用SQL来执行此操作。您需要编写一个简短的Java程序来列出所需的表名及其列名,然后为每个表构造一个UPDATE语句并执行它。

使用Oracle,您可以在PL / SQL中编写相同的程序。但Java语言解决方案与两个数据库引擎兼容。