使用从同一个表计算的值更新表的最佳方法

发布于 2024-12-12 03:47:22 字数 1113 浏览 0 评论 0原文

我对sql完全是菜鸟。我认为最好的方法是做到这一点;我有包含这些字段的收据表:

Receipt
-------
ReceiptID, AssociatedReceiptID, Value, Total

我想用它们的值字段的总和更新具有相同 AssociatedReceiptID 的所有行的总计字段。所以我尝试了下一条sql语句:

UPDATE Receipt r1
SET Total = (SELECT sum(Value)
             FROM Receipt r2
             WHERE r2.AssociatedReceiptID = r1.AssociatedReceiptID
             GROUP BY r2.AssociatedReceiptID)

该表中有超过100000条记录,持续了17个多小时。由于我正在更新正在查询的同一个表,因此我决定将其拆分为两个更新语句,将总和结果存储在临时表(其中有 )中,然后使用这些值更新收据表。

UPDATE TemporaryTable t1
SET Total = (SELECT sum(Value)
             FROM Receipt r2
             WHERE r2.AssociatedReceiptID = t1.AssociatedReceiptID
             GROUP BY r2.AssociatedReceiptID)

UPDATE Receipt r1
SET Total = (SELECT Total
             FROM TemporaryTable t1
             WHERE t1.ReceiptID = r1.ReceiptID)

使用这些语句,更新过程需要 6-7 小时。但我确信应该有更好的方法来做到这一点。简而言之,这些是我的问题:

  • 你如何以更好的方式做到这一点?
  • 更新语句中的子查询每更新一行就执行一次,不是吗?因此,如果有 10 行具有相同的 AssociatedReceiptID,则总和将计算 10 次。如何在更新语句中为每个 AssociatedReceiptID 只计算一次总和?

提前致谢。

I'm totally noob in sql. I think the best way to do this; I have Receipt table with theese fields:

Receipt
-------
ReceiptID, AssociatedReceiptID, Value, Total

I want to update Total field of all rows with the same AssociatedReceiptID with the sum of their Value fields. So I've tried the next sql statement:

UPDATE Receipt r1
SET Total = (SELECT sum(Value)
             FROM Receipt r2
             WHERE r2.AssociatedReceiptID = r1.AssociatedReceiptID
             GROUP BY r2.AssociatedReceiptID)

With more of 100000 records in this table, it last over 17 hours. Because of I'm updating the same table I'm quering, I decided to split it in two updates statements, storing sum result in a temporary table (which has ) and then updating Receipt table with these values.

UPDATE TemporaryTable t1
SET Total = (SELECT sum(Value)
             FROM Receipt r2
             WHERE r2.AssociatedReceiptID = t1.AssociatedReceiptID
             GROUP BY r2.AssociatedReceiptID)

UPDATE Receipt r1
SET Total = (SELECT Total
             FROM TemporaryTable t1
             WHERE t1.ReceiptID = r1.ReceiptID)

Using these statements, update process takes 6-7 hours. But I'm sure there should be a better way of do this. So, in brief, these are my questions:

  • How do yo do this in a better way?
  • Subquery in update statements is executed once per row updated, isn't it? So, if there are 10 rows with same AssociatedReceiptID, sum is calculated 10 times. How can I calculate sum only once per AssociatedReceiptID in the update statement?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

离笑几人歌 2024-12-19 03:47:22

尝试在内存中创建一个临时表:

DECLARE @temp_receipts TABLE (
AssociatedReceiptID int,
sum_value int)

然后:

insert into @temp_receipts
SELECT AssociatedReceiptID, sum(Value)
FROM Receipt
GROUP BY AssociatedReceiptID

然后更新主表总计:

UPDATE Receipt r
SET Total = (SELECT sum_value
             FROM @temp_receipts tt
             WHERE r.AssociatedReceiptID = tt.AssociatedReceiptID)

但是,我会创建一个名为receipt_totals或其他内容的表并使用它。在每个相关行中包含每个相关收据的总计是没有意义的。如果您这样做是为了查询方便,请考虑在receipts和receipt_totals之间创建一个视图

try creating a temp table in memory:

DECLARE @temp_receipts TABLE (
AssociatedReceiptID int,
sum_value int)

then:

insert into @temp_receipts
SELECT AssociatedReceiptID, sum(Value)
FROM Receipt
GROUP BY AssociatedReceiptID

and then update the main table totals:

UPDATE Receipt r
SET Total = (SELECT sum_value
             FROM @temp_receipts tt
             WHERE r.AssociatedReceiptID = tt.AssociatedReceiptID)

However, I would create a table called receipt_totals or something and use that instead. It makes no sense to have the total of each associated receipt in every single related row. if you are doing it for query convenience consider creating a view between receipts and receipt_totals

GRAY°灰色天空 2024-12-19 03:47:22

最初,您可以按照问题中建议的方式进行。

对于一行的每次更改,我认为最好使用数据库触发器。他们将更新每一行的值。

您可以阅读有关 MySQL 中触发器的信息 在这里

您可能需要使用 InnoDB 作为存储引擎。

如果您不使用 MySQL,请检查与您的 DBMS 相对应的参考资料。

Initially you may go the way you suggest in the question.

For each change for one row I think it would be better to use database triggers. They will update the value for each row.

You can read about triggers in MySQL here.

You may need to use InnoDB as a storage Engine.

If you do not use MySQL please check the reference corresponding your DBMS.

诠释孤独 2024-12-19 03:47:22
MERGE INTO Receipt r
USING (
        SELECT sum(Value) s, AssociatedReceiptID
        FROM Receipt           
        GROUP BY AssociatedReceiptID
      ) r_sum 
ON( r.AssociatedReceiptID = r_sum.AssociatedReceiptID)
WHEN MATCHED THEN UPDATE
set r.Total = r_sum.s
;
MERGE INTO Receipt r
USING (
        SELECT sum(Value) s, AssociatedReceiptID
        FROM Receipt           
        GROUP BY AssociatedReceiptID
      ) r_sum 
ON( r.AssociatedReceiptID = r_sum.AssociatedReceiptID)
WHEN MATCHED THEN UPDATE
set r.Total = r_sum.s
;
遮了一弯 2024-12-19 03:47:22

我知道这是一个老问题,但我认为更好的方法是这样。

UPDATE r1
    SET r1.Total = r2.sumValue

FROM Receipt r1
    INNER JOIN 
        (SELECT sum(Value) sumValue,AssociatedReceiptID
        FROM Receipt rSum
        GROUP BY rSum.AssociatedReceiptID) r2 ON r2.AssociatedReceiptID = r1.AssociatedReceiptID

这就是一次查询和计算的全部内容。

希望它有用。

I know this is an old question but I think a better way is this.

UPDATE r1
    SET r1.Total = r2.sumValue

FROM Receipt r1
    INNER JOIN 
        (SELECT sum(Value) sumValue,AssociatedReceiptID
        FROM Receipt rSum
        GROUP BY rSum.AssociatedReceiptID) r2 ON r2.AssociatedReceiptID = r1.AssociatedReceiptID

Here's all in one query and calculaton just one.

Hope it's usefull.

爱她像谁 2024-12-19 03:47:22

对于大型表,将表复制到新表(并同时进行更改)比更新它要快得多(至少在 Oracle DB 上)。

例如: 比

update table1 set some_num = some_num +1 where year = 2010;

:(

create table table1b as
  select (case when year = 2010 then some_num+1 else some_num) as some_num,
      other, columns, of, the, table
  from table1;
drop table1;
rename table1b to table1; -- also fix or recreate constraints

从表中删除行也是如此:将应保留的所有行复制到新表中,然后重命名它,而不是在原始表上进行常规 DELETE)

所以在您的情况下将会是:

create table ReceiptNew as
    select ReceiptID, AssociatedReceiptID, Value,
        sum(value) over (partition by AssociatedReceiptID) 
        as Total
    from Receipt;

drop table Receipt;
rename ReceiptNew to Receipt;

同样,您必须重新设置表上的约束(“NOT NULL”除外,它们会自动继承)。

For large tables, copying the table to a new one (and doing the changes at the same time) is much faster (at least on Oracle DB) than updating it.

For example:

update table1 set some_num = some_num +1 where year = 2010;

is much slower than:

create table table1b as
  select (case when year = 2010 then some_num+1 else some_num) as some_num,
      other, columns, of, the, table
  from table1;
drop table1;
rename table1b to table1; -- also fix or recreate constraints

(this is true also for deleting rows from the table: copy all rows that should remain into a new table and then rename it, instead of a regular DELETE on the original table)

So in your case it would be:

create table ReceiptNew as
    select ReceiptID, AssociatedReceiptID, Value,
        sum(value) over (partition by AssociatedReceiptID) 
        as Total
    from Receipt;

drop table Receipt;
rename ReceiptNew to Receipt;

Again, you must re-set the constraints on the table (except "NOT NULL", they get carried over automatically).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文