How to do an update from a select with summarized registers in SQLServer

A very powerful way to do a table's update in a SQL Server database is to link it with another table with a join, and updating the fields of everyone of its registers using the field's values of the registers linked with the another one. This technique had been discussed in the forum post Update with join or update from select in SQL Server .

Update from summarized register

An example of Update with join:

Update table1
set table1field1 = t2.table2field1
from table1 t1, table2 t2
where t1.fieldX = t2.fieldX

 

If the field that is doing the join is key in the second table, there is no problem, the update will work perfectly. We are having a problem when it is not the case, and linking with the use of that field, to each register of the first table may correspond more than one of the latter. In that case, we can find unexpected results because the update will be done with the value of only one of the registers in the link with each register of the first table.

If the correspondence is from one to several registers and we want to save in every field of the first table an added value, such as the sum of all records that are mapped in the second table, we have to write a more complicated sentence.  

 

How to do an update with join from summarized registers

The we can think to solve it, is using directly the aggregation function in the SET, assignating the field value of the second table overwriting the preview from the first one. It would be something similar to the following: 

Update table1
set table1field1 = sum(t2.table2field1)
from table1 t1, table2 t2
where t1.fieldX = t2.fieldX

 

We have added the sum function in the assignment of the second field. It would be great if SQL Server would be capable of understand our intentions, but as a result of this, the software returns us the following message error:

Mess. 157, Level 15, Status 1, Line 2      
Aggregate may not appear in the set list of an UPDATE statement.

 

And then what do we do? A simple solution is to create a view or an alias that returns the result of the aggregation of the second table to the UPDATE, and make that the join of the update will be capable of find in this view a single register for each register in the table to update.

It's about creating a view or a table alias with the join of the two tables and the value added for each register in the source table where we want to do the update. 

The information we need are the key fields of each register of the table, and the calculated value for each of them.

 

This would be the SELECT with the identifiers and the added value for each record in the source table:

SELECT fieldX, SUM(t2.table2field1)
FROM table1 t1, table2 t2
WHERE t1.fieldX=t2.fieldX 
GROUP BY t1.fieldX

Then the Update statement using this select with an alias would be as follows:

UPDATE table1
SET table1field1 = table2summarized.field1summarized
FROM table1 t1, (SELECT fieldX, SUM(t2.table2field1) field1summarized
                          FROM table1 t1, table2 t2
                          WHERE t1.fieldX=t2.fieldX
                          GROUP BY t1.fieldX)  table2summarized
WHERE t1.fieldX = table2summarized.fieldX

And so for each record in the first table, to field1 will be assigned the sum of the values ​​from table2field1 that will be linked doing the join with the other table by fieldX.

It can be very useful when we want to update table fields with values ​​from other tables at different levels of aggregation. For example, the amount in one table with the invoice headers, calculated from the amounts of another table containing the lines or the detail of those bills.

 

Do you know or you think of a more efficient, smarter or simply different to get the same?

 

Do you find useful this SQL tip? Use the 'SHARE' button to share with your colleagues! 

 

By Carlos Fernández