简体   繁体   中英

update a sql using subquery and aggregate function

Below is a SQL query where I am getting the error

returns more than 1 value

Query:

update Tab2 
set monthly_calls = 
    (select a.month 
     from 
          (select accountid, max(annual_calls)/12 as month 
           from cpo 
           group by accountid) a 
     inner join tab2 on tab2.accountid = a.accountid)

FYI... my select query which is left of = is working fine

If you select query which is left of = returns multiple records then it will not be executed.

So please try to get only 1 record out of that.

Only one record can be updates at a time using this update statement, so you must make sure that only one record is returned by that query.

Try this.

update Tab2 
set monthly_calls = 
    (select top 1 a.month 
     from 
          (select accountid, max(annual_calls)/12 as month 
           from cpo 
           group by accountid) a 
     inner join tab2 on tab2.accountid = a.accountid)
update Tab2 
set monthly_calls = a.month 
from 
     (select accountid, max(annual_calls)/12 as month 
      from cpo 
      group by accountid) a 
inner join tab2 on tab2.accountid = a.accountid

I think the logic you're using needs to be reviewed as well. The column annual_calls - does it get updated once a year, or is it updated at the end of every month? The reason I ask is if this were for a new system with only 6 months worth of calls, the monthly_calls field would be set to a value of approximately half of what it should be.

I would suggest also renaming monthly_calls to avg_monthly_calls or something more meaningful because if someone were to come in, look at your database schema and try to work out what is what, they might think that field holds total monthly calls or expected monthly calls.

As for the statement to update the data - without seeing any sort of data, here's a neater way of using an UPDATE statement without subselects:

UPDATE
    Tab2
SET
    monthly_calls = MAX(annual_calls) / 12
FROM
    CPO INNER JOIN Tab2 ON CPO.accountid = Tab2.accountid
WHERE
    YEAR([Tab2.DateField]) = @YearToUpdate
GROUP BY
    CPO.accountid

This basically takes care of the subselect by including a FROM clause in the UPDATE statement. That way you can join and update all at once.

Edit: I would also add in a WHERE clause so you can set it so you update only the current year, or the previous year, or whatever year/period you pass in. That way, you ensure you only get one record for each account for each year.

You are trying to set monthly_calls variable's value by using a select statement that returns a set of rows. Try using an aggregate function on a.month like max().

Standard SQL requires scalar subqueries, which in this case is arguably simpler than joins anyhow:

UPDATE Tab2 
   SET monthly_calls = (
                        SELECT MAX(annual_calls) / 12
                          FROM cpo 
                         WHERE tab2.accountid = cpo.accountid
                       )
 WHERE EXISTS (
               SELECT *
                 FROM cpo
                WHERE tab2.accountid = cpo.accountid
              );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM