我在sql中完全是noob。我认为这是最好的方法;我有theese字段的收据表:
Receipt
-------
ReceiptID, AssociatedReceiptID, Value, Total
我想更新具有相同AssociatedReceiptID的所有行的Total字段及其Value字段的总和。所以我尝试了下一个sql语句:
UPDATE Receipt r1
SET Total = (SELECT sum(Value)
FROM Receipt r2
WHERE r2.AssociatedReceiptID = r1.AssociatedReceiptID
GROUP BY r2.AssociatedReceiptID)
此表中有超过100000条记录,持续时间超过17小时。因为我正在更新我正在查询的同一个表,所以我决定将它拆分为两个更新语句,将sum结果存储在临时表(有)中,然后用这些值更新Receipt表。
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个小时。但我确信应该有更好的方法来做到这一点。所以,简而言之,这些是我的问题:
提前致谢。
答案 0 :(得分:2)
尝试在内存中创建临时表:
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的表,然后使用它。在每个相关行中包含每个关联收据的总数是没有意义的。如果你是为了方便查询而考虑在收据和receipt_totals之间创建一个视图
答案 1 :(得分:1)
最初,你可能会按照你在问题中的建议去做。
对于一行的每次更改,我认为使用数据库触发器会更好。他们将更新每一行的值。
您可以阅读MySQL here中的触发器。
您可能需要将InnoDB用作存储引擎。
如果您不使用MySQL,请检查与您的DBMS相对应的参考。
答案 2 :(得分:0)
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
;
答案 3 :(得分:0)
我知道这是一个老问题,但我认为更好的方法就是这个。
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
这里只有一个查询,只计算一个。
希望它有用。
答案 4 :(得分:0)
对于大型表,将表复制到新表(并同时进行更改)比更新表要快得多(至少在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"除外,它们会自动转移)。