【问题标题】:Update with count and group by expressions使用 count 和 group by 表达式更新
【发布时间】:2021-06-10 05:19:16
【问题描述】:

首先,我知道 Stack Overflow 中存在一个常见问题,但以下解决方案在这里效果不佳。所以我仍然需要一些帮助。

Oracle - Update COUNT of rows with specific value

Oracle - Update rows with a min value in the group of a column from another table

Oracle update statement with group function

Oracle - Update COUNT of rows with specific value

问题是:我有一个 +700k 行表:

REVIEWS (PRODUCT_ID, REVIEW, REVIEW_DATE, RELEASE_DATE, ..., REVIEW_COUNT)

我正在尝试通过计算具有相同 PRODUCT_ID 的行来更新 REVIEW_COUNT(我只想在产品发布之前进行评论)。所以下面的代码非常适合我的目的:

SELECT COUNT(PRODUCT_ID) FROM REVIEWS
WHERE REVIEW_DATE < RELEASE_DATE 
GROUP BY PRODUCT_ID 

但我很难进行更新。首先我尝试了这个:

UPDATE REVIEWS R
SET R.REVIEWS_COUNT = 
(SELECT COUNT(RR.PRODUCT_ID) FROM REVIEWS RR
WHERE RR.DATA < RR.REL_DATE
GROUP BY RR.PRODUCT_ID)

错误是“多于一行”,这并不奇怪,但由于我使用的是 group by 语句,所以它不应该发生。所以我尝试了自加入:

UPDATE REVIEWS R
SET R.REVIEWS_COUNT = 
(SELECT COUNT(RR.PRODUCT_ID) FROM REVIEWS RR
WHERE RR.PRODUCT_ID = R.PRODUCT_ID AND RR.DATA < RR.REL_DATE)

但是查询需要很长时间,我认为这不应该花这么长时间,简单的选择非常正常 - 快速。 我还测试了一些更花哨、更简单的东西,但结果还是一样:等待了很长时间,而且似乎是错误的。 请问,我在如此简单的更新中缺少什么?

【问题讨论】:

    标签: oracle sql-update


    【解决方案1】:

    也许你可以定义视图而不是更新:

    select product_id, review_date, release_date, 
           count(case when review_date < release_date then 1 end)
           over (partition by product_id) review_count
      from reviews;
    

    你也可以试试merge,而不是update

    merge into reviews a 
    using (select product_id, count(product_id) cnt from reviews
            where review_date < release_date 
            group by product_id ) b
    on (a.product_id = b.product_id)
    when matched then update set reviews_count = b.cnt
    

    dbfiddle

    【讨论】:

    • 。我使用视图作为我的工作,但正如我对 Roger Cornejo 所说,我无法更新我的表似乎是不对的。除了 700k 表之外,更新本身大约只有 15k。我认为这应该不是问题。我只是想知道为什么更新不适合这种情况。无论如何,合并非常适合我的需求。谢谢!
    • 视图,或者物化视图,推荐使用,当数据变化时你不必更新任何东西。但如果你想要它,你可以更新或合并。 merge 更紧凑,只准备一次数据,并将此集合用于更新子句。我经常在类似的情况下使用它,甚至使语法更短。当您进行此类更新或聚合时,product_id 上的索引是强制性的。
    【解决方案2】:

    我认为您的第二次更新是正确的:

    UPDATE REVIEWS R
    SET R.REVIEWS_COUNT = 
    (SELECT COUNT(RR.PRODUCT_ID) FROM REVIEWS RR
    WHERE RR.PRODUCT_ID = R.PRODUCT_ID AND RR.DATA < RR.REL_DATE)
    ;
    

    这将更新评论表中的每条记录。这是你想要的吗?

    product_id 上的索引将使内部查询运行得更快,但仍会更新所有 700K 左右的记录。

    【讨论】:

    • 是的,REVIEWS_COUNT 列目前是空的,所以我需要更新所有记录。现在,我把这个 REVIEWS 表变成了一个较小的表,只有 ids(大约 15k 行)并且我可以使用,因为无论如何我都需要分组。但是不希望我需要以这种方式解决...查询本身没有错,对吗?为什么这需要这么长时间?我的意思是,让更新运行 2 个小时,什么也没发生。
    • @user13013458 根据我对您的要求的基本了解,更新对我来说还不错。您是否检查了 product_id 上是否有索引?这将是加快速度的最佳方式。否则它需要做 700K 加上全表扫描。还有其他事情需要检查:1)阻塞lockw 2)如果表非常大或碎片,则完整扫描会更长。
    • 我检查了一个索引,但没有。我一直在努力,但似乎和以前一样长。也许是我的 XE Oracle 版本和我的“伟大”计算机。我只是一个资源非常有限的学生,我也应该考虑一下。无论如何感谢您的提示,索引加快了其他进程。
    猜你喜欢
    • 2013-10-17
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 2015-10-30
    • 2016-07-23
    • 2021-08-01
    • 2014-05-20
    相关资源
    最近更新 更多