Update multiple rows with data from another table - sql

I have to update 700 rows on a table. Is it possible to do it with only one query?
2 examples:
UPDATE PERSON p SET p.admin = (select usr.iqid from USER usr where usr.userid = 'J072') where upper(person.myid) = '18349';
UPDATE PERSON p SET p.admin = (select usr.iqid from USER usr where usr.userid = 'PU96') where upper(person.myid) = '36895';

I would write this as:
UPDATE PERSON p
SET p.admin = (SELECT u.iqid
FROM USER u
WHERE (u.userid = 'J072' AND p.myid = '18349') OR
(u.userid = 'PU96' AND p.myid = '36895')
)
WHERE p.myid IN ('18349', '36895');
Notes that upper() is not needed for numbers. It would generally impede the use of indexes.

Option 1.
update person p
set p.admin =
(select usr.iqid
from user usr
where usr.userid = decode(upper(person.myid), '36895', 'PU96', '18349', 'J072'))
where upper(person.myid) = any ('36895', '18349');
Option 2.
Use merge statement to avoid correlated scalar subquery.
Option 3.
Update (select ... from person join user) set ... if person has foreign key references user.
Google "key preserned view".

Related

Getting SQL Server Merge Error

I am trying to update the product history's average rating number by using the merge function
MERGE ProductRankingHistory P
USING Review R ON P.PRHProduct = R.ProductID
WHEN MATCHED THEN
UPDATE
SET P.PRHAverageRating = (SELECT AVG(ReviewRateValue)
FROM Review
WHERE ProductID = P.PRHProduct
AND YEAR(ReviewRateDate) = PRHYear);
And I get this error:
Msg 8672, Level 16, State 1, Line 2
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Merge seems unnecessary for this logic. Something like:
UPDATE ProductRankingHistory P
SET PRHAverageRating = (SELECT AVG(r.ReviewRateValue)
FROM Review r
WHERE r.ProductID = P.PRHProduct AND YEAR(r.ReviewRateDate) = P.PRHYear
)
WHERE EXISTS (SELECT 1
FROM Review r
WHERE r.ProductID = P.PRHProduct AND YEAR(r.ReviewRateDate) = P.PRHYear
);
After writing this, I see that you are probably using SQL Server (or a similar database). The following might work:
UPDATE p
SET PRHAverageRating = rp.avg_ReviewRateValue
FROM ProductRankingHistory p JOIN
(SELECT r.ProductID, YEAR(r.ReviewRateDate) as yyyy, AVG(r.ReviewRateValue) as avg_ReviewRateValue
FROM Review r
GROUP BY r.ProductID, YEAR(r.ReviewRateDate)
) rp
ON rp.ProductId = p.PRHProduct AND rp.yyyy = p.prhYear;

SQL If statement for specific user

So I have 2 users, one called admin, the other one called admin2.
I have wrote a SQL query in which I want to increase an achievement of a specific account, in my case only for admin, but inspite of that, the same achievement for user admin2 is also affected. What am I doing wrong?
DECLARE #Achievement1 INT
SELECT #Achievement1 = Achievement1
FROM [dbo].[Achievement]
WHERE [dbo].[Achievement].UserID = (SELECT [AccountID]
FROM [dbo].[Account]
WHERE [Username] = 'Admin')
IF (#Achievement1 < 100)
UPDATE [dbo].[Achievement]
SET [Achievement1] += 2
ELSE
UPDATE [dbo].[Achievement]
SET [Achievement1] += 0
Your code is updating all rows in Achievement when the condition is met. It is not just updating the matching row.
Your logic is rather convoluted. I think you can just do this:
UPDATE a
SET Achievement1 += 2
FROM dbo.Achievement a
WHERE a.Achievement1 < 100 AND
a.UserId = (SELECT ac.AccountId
FROM dbo.Account ac
WHERE ac.UserName = 'admin'
);
Note: Having UserId in one table match AccountId in another is quite confusing. Are you sure the comparison should not be either user ids or account ids?
No need for all of this, you can just update with join like this:
UPDATE a1
SET a1.[Achievement1] = CASE WHEN a1.Achievement1 < 100 THEN a1.[Achievement1] + 2
ELSE a1.[Achievement1] END
FROM [dbo].[Achievement] AS a1
INNER JOIN [dbo].[Account] AS a2 ON a1.UserID = a2.[AccountID]
WHERE a2.UserName = 'admin';

DB2 Update with subquery that contains join - correlating

I am trying to perform an update with a subquery where the update table is joined in the subquery. I cannot figure out how to associate the update record with the record found in the subquery. Something like the following, though as written this will obviously update the entire table. Thanks in advance.
Update OPTION OPT
SET (PSTREET, PCITY, PPROVINCE, PCOUNTRY, PPOSTALCODE)=
(select ADDRESS, CITY, PROVSTATE, COUNTRY, POSTALCODE
from ADDRESSES addr INNER JOIN COMPANY C ON C.SECURITYCOMPANY = addr.CODE1 || addr.CODE2
INNER JOIN DCODE D ON C.COMPANY_ID = D.COMPANY_ID
INNER JOIN OPTION OPT ON OPT.DCODE_ID = D.DCODE_ID
WHERE C.YEAROF IS NULL
AND C.DELETED IS NULL
AND D.DCODEEFF < CURRENT TIMESTAMP
AND (D.DCODEEXP IS NULL OR D.DCODEEXP > CURRENT TIMESTAMP)
AND D.DCODEELEMENT = addr.DCODEELEMENT
AND D.IND = addr.IND
AND ((addr.IND = 'B' AND addr.VAL1 = OPT.VAL1 AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'Y' AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'X' AND addr.VAL1 = OPT.VAL1))
You need to have some criteria to identify the records in OPT that you want to update. If its a single record, you'll need a surrogate or natural key. If its a many records like, say, based on a timestamp, you will need that time. Those criteria can then be put into a where clause after your set.
Use a condition in the WHERE clause in the sub-query that ties the result(s) in the sub-query to the outer table that you're updating. Here I added AND addr.addr_id = OPT.addr_id to your WHERE clause, but whatever the id column is called it needs to be shared between the table that you are updating and the sub-query.
UPDATE OPTION OPT
SET (PSTREET, PCITY, PPROVINCE, PCOUNTRY, PPOSTALCODE) =
(SELECT ADDRESS, CITY, PROVSTATE, COUNTRY, POSTALCODE
FROM ADDRESSES addr INNER JOIN COMPANY C ON C.SECURITYCOMPANY = addr.CODE1 || addr.CODE2
INNER JOIN DCODE D ON C.COMPANY_ID = D.COMPANY_ID
INNER JOIN OPTION OPT ON OPT.DCODE_ID = D.DCODE_ID
WHERE C.YEAROF IS NULL
AND C.DELETED IS NULL
AND D.DCODEEFF < CURRENT TIMESTAMP
AND (D.DCODEEXP IS NULL OR D.DCODEEXP > CURRENT TIMESTAMP)
AND D.DCODEELEMENT = addr.DCODEELEMENT
AND D.IND = addr.IND
AND ((addr.IND = 'B' AND addr.VAL1 = OPT.VAL1 AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'Y' AND addr.VAL2 = OPT.VAL2)
OR (addr.IND = 'X' AND addr.VAL1 = OPT.VAL1)
AND addr.addr_id = OPT.addr_id)
In reality the criteria might be more complicated (involving a compound key or some inequality condition, for instance) - but regardless, adding the condition to the inner query is what's required.

Oracle database. How to update selected columns.

the problem is:
I have two tables(column names are in brackets):
Cars (CarColorId, CarName), CarColor (CarColorId, CarColorName);
The task is to UPDATE Cars.CarName with a string "_updated" but only if CarColor.CarColorName = 'red'. I have know idea how to do this without joins
I have tried this way:
UPDATE Cars set CarName = concat (CarName, '_updated') WHERE CarColorId = 1;
CarColorId = 1 = red;
This request works, but the task is to use both tables
You can try any one of this in Oracle
Normal Update
UPDATE
CARS
SET
CARS.CARNAME =
CONCAT ( CARS.CARNAME,
'_updated' )
WHERE
EXISTS
(SELECT
CARCOLOR.CARCOLORID
FROM
CARCOLOR
WHERE
CARS.CARCOLORID = CARCOLOR.CARCOLORID
AND CARCOLOR.CARCOLORNAME = 'RED');
Using Inline View (If it is considered updateable by Oracle)
Note: If you face a non key preserved row error add an index to resolve the same to make it update-able
UPDATE
(SELECT
CARS.CARNAME AS OLD,
CONCAT ( CARS.CARNAME,
'_updated' )
AS NEW
FROM
CARS
INNER JOIN
CARCOLOR
ON CARS.CARCOLORID = CARCOLOR.CARCOLORID
WHERE
CARCOLOR.CARCOLORNAME = 'RED') T
SET
T.OLD = T.NEW;
Using Merge
MERGE INTO
CARS
USING
(SELECT
CARS.ROWID AS RID
FROM
CARS
INNER JOIN
CARCOLOR
ON CARS.CARCOLORID = CARCOLOR.CARCOLORID
WHERE
CARCOLOR.CARCOLORNAME = 'RED')
ON
( ROWID = RID )
WHEN MATCHED
THEN
UPDATE SET CARS.CARNAME =
CONCAT ( CARS.CARNAME,
'_updated' );
You can modify your query like this:
UPDATE
Cars
set
CarName = concat (CarName, '_updated')
WHERE
CarColorId in (
select
CarColorId
from
CarColor
where
CarColorName='red'
)
;
I know you said that you did not know how to do this without any joins. I don't know if that means you would prefer to avoid joins or whether you would be open to the possibility of using them if you could. If the latter is the case then check out this piece of code:
UPDATE
(
SELECT c.CarName, cc.CarColorName
FROM Cars c
INNER JOIN CarColors cc
ON c.CarColorId = cc.CarColorId
) CarsWithColor
SET CarsWithColor.CarName = CarsWithColor.CarName || '_Updated'
WHERE CarsWithColor.CarColorName = 'red';
Hope this helps also.
T

Can I update multiple fields in a table with aggregated data from other table, in Postgres?

I figured out how to do one field at a time (see two update queries below). Is there a way to do this in a single query?
UPDATE upload_data sd
SET
photo_count =
(SELECT sum(photo_count)
FROM media_uploads mu
WHERE mu.user_id=sd.user_id
AND mu.date=current_date
GROUP BY mu.user_id);
UPDATE upload_data sd
SET
video_count =
(SELECT sum(video_count)
FROM media_uploads mu
WHERE mu.user_id=sd.user_id
AND date_trunc('month', mu.date)=date_trunc('month', sd.date)
GROUP BY mu.user_id);
I think you can do this by JOIN with UPDATE. In postgresql as the UPDATE syntax, it will be this way:
UPDATE upload_data sd
SET sd.photo_count = m.photo_count,
sd.video_count = m.video_count
FROM
(
SELECT
user_id,
sum(photo_count) AS photo_count,
SUM(video_count) AS video_count
FROM media_uploads
WHERE mu.date = current_date
GROUP BY user_id
) AS m
WHERE m.user_id = sd.user_id;