【问题标题】:Can a DB2 WITH statement be used as part of an UPDATE or MERGE?可以将 DB2 WITH 语句用作 UPDATE 或 MERGE 的一部分吗?
【发布时间】:2011-02-01 15:20:05
【问题描述】:

我需要更新数据库表中的一些行。我如何识别要更新的行涉及一系列复杂的语句,我设法将它们归结为一系列 WITH 语句。现在我有了正确的数据值,我需要更新表格。

由于我设法通过 WITH 语句获取这些值,因此我希望在 UPDATE/MERGE 中使用它。一个简化的例子如下:

with data1
(
    ID_1
)
as
(
    Select ID
    from  ID_TABLE
    where ID > 10
)
,
cmedb.data2
(
     MIN_ORIGINAL_ID
    ,OTHER_ID
)
as
(
    Select min(ORIGINAL_ID)
           ,OTHER_ID
    from   OTHER_ID_TABLE
    where  OTHER_ID in
    (
        Select distinct ID_1
        From   data1
    )
    group by OTHER_ID

)
select MIN_ORIGINAL_ID
      ,OTHER_ID
from cmedb.data2

现在我有两列数据,我想用它们来更新一个表。因此,我没有在底部使用 select,而是尝试了各种合并和更新的组合,包括在 UPDATE/MERGE 上方使用 WITH 语句,或者作为 UPDATE/MERGE 语句的一部分。以下是我心中最接近我想做的事情:

merge into ID_TABLE as it
using
(
    select MIN_ORIGINAL_ID
          ,OTHER_ID
    from cmedb.data2

) AS SEL
ON
(
    it.ID = sel.OTHER_ID
)
when matched then
update
set it.ORIGINAL_ID = sel.MIN_ORIGINAL_ID

所以它不起作用。我不确定这是否可能,因为我在互联网上没有找到将 WITH 语句与 UPDATE 或 MERGE 结合使用的示例。我有 WITH 语句与 INSERT 结合使用的示例,因此相信它是可能的。

如果有人可以提供帮助,那就太好了,如果我遗漏了任何有助于解决问题的信息,请告诉我。

免责声明:我提供的示例是我正在尝试做的简化版本,实际上可能没有任何意义!

【问题讨论】:

    标签: join merge db2 with-statement


    【解决方案1】:

    正如@Andrew White 所说,您不能在 MERGE 语句中使用公用表表达式。

    但是,您可以使用嵌套子选择消除公用表表达式。这是您的示例选择语句,使用嵌套子选择重写:

    select min_original_id, other_id
    from (
       select min(original_id), other_id
       from   other_id_table
       where  other_id in (
          select distinct id_1 from (select id from id_table where id > 10) AS DATA1 (ID_1)
       )
       group by other_id
    ) AS T (MIN_ORIGINAL_ID, OTHER_ID);
    

    这有点令人费解(确切的陈述可以写得更好),但我意识到你只是给出了一个简化的例子。

    您可以使用嵌套子选择而不是公用表表达式来重写您的 MERGE 语句。这在语法上当然是可能的。

    例如:

    merge into other_id_table x
    using (
       select min_original_id, other_id
       from (
          select min(original_id), other_id
          from   other_id_table
          where  other_id in (
             select distinct id_1 from (select id from id_table where id > 10) AS DATA1 (ID_1)
          )
          group by other_id
       ) AS T (MIN_ORIGINAL_ID, OTHER_ID)
    ) as y
    on y.other_id = x.other_id
    when matched 
       then update set other_id = y.min_original_id;
    

    同样,这很令人费解,但它向您表明它至少是可能的。

    【讨论】:

    • 优秀。这就是我最终要做的。一位同事居然建议这样做,我忽略了他...
    【解决方案2】:

    一种将 WITH 语句与 UPDATE(以及 INSERT 也是)一起使用的方法是使用 SELECT FROM UPDATE 语句(here):

    WITH TEMP_TABLE AS (
        SELECT [...]
    )
    SELECT * FROM FINAL TABLE (
        UPDATE TABLE_A SET (COL1, COL2) = (SELECT [...] FROM TEMP_TABLE)
        WHERE [...]
    );
    

    【讨论】:

    • 嗨,这正是我要找的,但你确定这有效吗?我得到一个-204,指的是 UPDATE 中的 TEMP_TABLE。 UPDATE 上下文中似乎不存在创建的表...
    • @bek 是的,工作正常。你能发布你的脚本吗?
    【解决方案3】:

    我现在正在查找语法,但我很确定答案是否定的。至少在我上次使用的 DB2 版本中没有。查看updatemerge 文档页面了解它们的语法。即使您在语法中看到 fullselect,您也不能使用 with,因为根据 select 文档页面,它是明确分开的。

    【讨论】:

      【解决方案4】:

      如果您运行的是 DB2 V8 或更高版本,有一个有趣的 SQL hack here 允许您在带有 WITH 语句的查询中进行 UPDATE/INSERT。对于需要大量初步数据准备的插入和更新,我发现这种方法非常清晰。

      编辑这里有一个更正 - 我相信 V9 中引入了从 UPDATE 语句中选择,因此上述内容适用于 V8 或更高版本的插入,以及 V9 或更高版本的更新。

      【讨论】:

        【解决方案5】:

        将 CTE 放入视图中,然后从合并中的视图中进行选择。通过这种方式,您将获得一个干净、可读的视图,以及一个干净、可读的合并。

        【讨论】:

          【解决方案6】:

          另一种方法是简单地替换您的 WITH 查询并仅使用子选择。

          例如,如果您有(并且我试图包含一个有点复杂的示例,其中包含一些 WHERE 逻辑、一个聚合函数 (MAX) 和一个 GROUP BY,只是为了展示它更真实的世界):

          WITH
            Q1 AS (
              SELECT
                A.X,
                A.Y,
                A.Z,
                MAX(A.W) AS W
              FROM
                TABLEB B
                INNER JOIN TABLEA A ON B.X = A.X AND B.Y = A.Y AND B.Z = A.Z
              WHERE A.W <= DATE('2013-01-01') 
              GROUP BY
                A.X,
                A.Y,
                A.Z
            ),
          
            Q2 AS (
              SELECT
                A.X,
                A.Y,
                A.Z,
                A.W,
                MAX(A.V) AS V
              FROM
                Q1
                INNER JOIN TABLEA A ON Q1.X = A.X AND Q1.Y = A.Y AND Q1.Z = A.Z AND Q1.W = A.W
              GROUP BY
                A.X,
                A.Y,
                A.Z,
                A.W
            )
          
          SELECT
            B.U,
            A.T
          FROM
            Q2
            INNER JOIN TABLEA A ON Q2.X = A.X AND Q2.Y = A.Y AND Q2.Z = A.Z AND Q2.W = A.W AND Q2.V = A.V)
            RIGHT OUTER JOIN TABLEB B ON Q2.X = B.X AND Q2.Y = B.Y AND Q2.Z = B.Z
          

          ...您可以通过执行以下操作将其变成适合 MERGE INTO 的内容:

          1. 删除顶部的 WITH
          2. 删除 Q1 块末尾的逗号(右括号后)
          3. 从左括号之前取出 Q1 AS,并将 is 放在结尾括号之后(删除逗号),然后将 AS 放在 Q1 前面。
          4. 获取这个新的 Q1 块并将其剪切并粘贴到 FROM Q1 之后的 Q2 块中(用剪贴板中的查询替换 Q1)注意:保留对 Q1 的其他引用(在内部连接键中)单独,当然。
          5. 现在您有一个更大的 Q2 查询。再次执行第 3 步和第 4 步,这次将主选择中的 Q2(在 FROM 之后)替换为剪贴板中较大的 Q2 查询。

          最后,您将得到一个如下所示的直接 SELECT 查询(重新格式化以显示正确的缩进):

          SELECT
            B.U,
            A.T
          FROM
            (SELECT
               A.X,
               A.Y,
               A.Z,
               A.W,
               MAX(A.V) AS V
             FROM
               (SELECT
                  A.X,
                  A.Y,
                  A.Z,
                  MAX(A.W) AS W
                FROM
                  TABLEB B
                  INNER JOIN TABLEA A ON B.X = A.X AND B.Y = A.Y AND B.Z = A.Z
                WHERE A.W <= DATE('2013-01-01') 
                GROUP BY
                  A.X,
                  A.Y,
                  A.Z) AS Q1
               INNER JOIN TABLEA A ON Q1.X = A.X AND Q1.Y = A.Y AND Q1.Z = A.Z AND Q1.W = A.W
               GROUP BY
                 A.X,
                 A.Y,
                 A.Z,
                 A.W) AS Q2
          INNER JOIN TABLEA A ON Q2.X = A.X AND Q2.Y = A.Y AND Q2.Z = A.Z AND Q2.W = A.W AND Q2.V = A.V
          RIGHT OUTER JOIN TABLEB B ON Q2.X = B.X AND Q2.Y = B.Y AND Q2.Z = B.Z
          

          我已经根据自己的个人经验(实际上只是现在)做到了这一点,并且效果很好。

          祝你好运。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-02-25
            • 1970-01-01
            • 1970-01-01
            • 2015-09-21
            • 2020-04-12
            • 2013-10-20
            • 1970-01-01
            • 2011-07-16
            相关资源
            最近更新 更多