使用从同一个表计算的值更新表的最佳方法
我对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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
尝试在内存中创建一个临时表:
然后:
然后更新主表总计:
但是,我会创建一个名为receipt_totals或其他内容的表并使用它。在每个相关行中包含每个相关收据的总计是没有意义的。如果您这样做是为了查询方便,请考虑在receipts和receipt_totals之间创建一个视图
try creating a temp table in memory:
then:
and then update the main table totals:
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
最初,您可以按照问题中建议的方式进行。
对于一行的每次更改,我认为最好使用数据库触发器。他们将更新每一行的值。
您可以阅读有关 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.
我知道这是一个老问题,但我认为更好的方法是这样。
这就是一次查询和计算的全部内容。
希望它有用。
I know this is an old question but I think a better way is this.
Here's all in one query and calculaton just one.
Hope it's usefull.
对于大型表,将表复制到新表(并同时进行更改)比更新它要快得多(至少在 Oracle DB 上)。
例如: 比
:(
从表中删除行也是如此:将应保留的所有行复制到新表中,然后重命名它,而不是在原始表上进行常规 DELETE)
所以在您的情况下将会是:
同样,您必须重新设置表上的约束(“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:
is much slower than:
(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:
Again, you must re-set the constraints on the table (except "NOT NULL", they get carried over automatically).