【问题标题】:Postgres bulk update on rows using multi-column subqueriesPostgres 使用多列子查询对行进行批量更新
【发布时间】:2012-01-17 06:19:58
【问题描述】:

我需要使用父表上 6 个字段的子表中的汇总值(计数、最小值、最大值)更新表(父表)中的所有行

tab1 (parent table)
-------------------
tab1_ID 
tab1_low
tab1_high
tab2_ref_count
tab2_ref_low
tab2_ref_high
tab3_ref_count
tab3_ref_low
tab3_ref_high
STUS_CD

tab2 (link table for tab1 to tab1)
----------------------------------
tab1_ID
tab1_ref_ID

tab3 (link table for tab1 to tab4)
----------------------------------
tab1_ID
tab4_ref_ID

tab4
-----
tab4_ID
tab4_low
tab4_high

要将 tab2 和 tab3 的计数汇总到 tab1,下面是我正在尝试的查询 -

UPDATE tab1
SET    (tab2_ref_count, tab2_ref_low, tab2_ref_high)  = 
                     (SELECT COUNT(t1.tab1_ID), MIN(t1.tab1_low),     MAX(t1.tab1_high)
                      FROM   tab2 t2 JOIN tab1 t1 ON (t2.tab1_ref_ID =     t1.tab1_ID) 
                      WHERE  tab1.tab1_ID = t2.tab1_ID),
       (tab3_ref_count, tab3_ref_low, tab3_ref_high)  = 
                     (SELECT COUNT(t4.tab4_ID), MIN(t4.tab4_low),       MAX(t4.tab4_high)
                      FROM   tab3 t3 JOIN tab4 t4 ON (t3.tab4_ref_ID =     t4.tab4_ID)
                      WHERE  tab1.tab1_ID = t3.tab1_ID)
WHERE  STUS_CD IN ('01','02')

但显然它不起作用。请问有什么建议吗?

【问题讨论】:

    标签: postgresql subquery rollup multiple-columns


    【解决方案1】:

    可以这样工作:

    UPDATE tab1 t1
    SET    tab2_ref_count = t2.ct
         , tab2_ref_low   = t2.low
         , tab2_ref_high  = t2.high
         , tab3_ref_count = t3.ct
         , tab3_ref_low   = t3.low
         , tab3_ref_high  = t3.high
    FROM  (
        SELECT t2.tab1_id
             , count(*)          AS ct
             , min(t1.tab1_low)  AS low
             , max(t1.tab1_high) AS high
        FROM  tab2 t2
        JOIN  tab1 t1 ON t1.tab1_id = t2.tab1_ref_id 
        GROUP BY 1
        ) t2
    JOIN  (
        SELECT t3.tab1_id
             , count(*)          AS ct
             , min(t4.tab1_low)  AS low
             , max(t4.tab1_high) AS high
        FROM   tab3 t3
        JOIN   tab4 t4 ON t4.tab4_id = t3.tab4_ref_id 
        GROUP  BY 1
        ) t3 USING (tab1_id)
    WHERE  stus_cd IN ('01','02')
    AND    t1.tab1_id = t2.tab1_id;
    -- AND    t1.tab1_id = COALESCE(t2.tab1_id, t3.tab1_id);  .. for FULL OUTER JOIN
    

    要点:

    • 我使用count(*) 而不是count(t4.tab1_id)。此处保证相同的结果,但更简单、更快。

    • 该查询假定tab3 中的每个tab1_id 中也存在tab2 中的行。如果不是这种情况,您必须将JOIN 类型更改为LEFT JOINFULL OUTER JOIN。在这种情况下,在最后的 WHERE 子句中使用提供的替代方案。

    • 如果在tab2tab3 中未找到相关行,则此查询根本不会更新tab1 中的行。

    【讨论】:

    • 感谢 Erwin 和 a_horse.... Erwin,根据您的第二个假设,tab2 和 tab3 中的 tab1_ID 之间没有关系。这可以解释为什么即使我使用 FULL OUTER JOIN UPDATE 只影响在 tab3 和 tab2 中有行的记录?我怎样才能解决这个问题?另外,在 UPDATE 语句中引入第三个链接表 tab5 和 tab6(对应的详细表),您认为性能会受到影响吗?运行 3 个单独的更新会更好吗?你有什么想法?
    • @user558122:如果您使用FULL OUTER JOIN,则我的免责声明不适用。它适用于我当前的版本,JOIN。至于你的第二个问题,请参阅我修改后的答案。当然,您可以随时吐出两个更新。会更容易理解,但速度较慢,因为行将被重复更新。如果你可以围绕这个解决方案:应该是最佳的。
    • 再次感谢欧文。出于某种原因,即使使用修改后的查询(FULL OUTER JOIN),查询仍然没有更新排他案例。它只更新 tab2 和 tab3 中都有行的地方。
    • @user558122:那不应该。我复查了。你确定你没有错别字吗?这是一个复杂的查询,很容易发生。或者您在 t2 / t3 中有条目,但在 t4 中没有匹配条目?
    • 我刚刚更正了我的原始帖子。我注意到一个错字。第一个链接表是一个自链接表(tab1 到 tab1)。我注意到的是 t2 中的记录在 t1 中有匹配的记录,但在 t3 中没有。对于这些记录,它们的聚合值在 t1 中没有更新。
    【解决方案2】:

    PostgreSQL 不支持更新语句中的元组定义(我认为这是计划好的)

    你可以使用这样的东西(未测试):

    UPDATE tab1
      SET tab2_ref_count = tt1.tab1_id_count, 
          tab2_ref_low = tt1.tab1_low_min, 
          tab2_ref_high = tt1.tab1_high_max
    FROM (
         SELECT COUNT(t1.tab1_ID) as tab1_id_count, 
                MIN(t1.tab1_low) as tab1_low_min,     
                MAX(t1.tab1_high) as tab1_high_max
         FROM  tab2 t2 
         JOIN tab1 t1 ON (t2.tab1_ref_ID = t1.tab1_ID) 
         WHERE  tab1.tab1_ID = t2.tab1_ID
     ) tt1
     ....
     WHERE  STUS_CD IN ('01','02')
    

    (在您的示例中,... 表示第二个子选择的第二个派生表)

    【讨论】:

      猜你喜欢
      • 2013-12-07
      • 2017-10-27
      • 2011-02-01
      • 2023-04-05
      • 2019-01-09
      • 2011-09-09
      • 1970-01-01
      • 2023-04-02
      • 2011-08-24
      相关资源
      最近更新 更多