Oracle database. How to update selected columns. - sql

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

Related

UPDATE statement with JOIN in SQL Server Not Working as Expected

I'm attempting to update the LAST_INSPECTION_FW field for all records in the VEHICLES_FW table with the last JOB_DATE_FW for records with the REASON_CODE_FW = 35. However, what's happening is that once the below code is executed, it's not taking into consideration the WHERE clause. This causes all of the records to update when it should just be updating those with the REASON_CODE_FW = 35.
Is there a way to restructure this code to get it working correctly? Please help, thanks!
UPDATE VEHICLES_FW
SET VEHICLES_FW.LAST_INSPECTION_FW = JOB_HEADERS_FW.FIELD2MAX
FROM VEHICLES_FW
INNER JOIN (SELECT VEHICLE_ID_FW, MAX(JOB_DATE_FW) AS FIELD2MAX
FROM JOB_HEADERS_FW
GROUP BY VEHICLE_ID_FW) AS JOB_HEADERS_FW
ON VEHICLES_FW.VEHICLE_ID_FW = JOB_HEADERS_FW.VEHICLE_ID_FW
INNER JOIN JOB_DETAILS_FW
ON JOB_NUMBER_FW = JOB_NUMBER_FW
WHERE REASON_CODE_FW = '35'
Common Table Expressions are your friend here. SQL Server's strange UPDATE ... FROM syntax is not. EG
with JOB_HEADERS_FW_BY_VEHICLE_ID as
(
SELECT VEHICLE_ID_FW, MAX(JOB_DATE_FW) AS FIELD2MAX
FROM JOB_HEADERS_FW
GROUP BY VEHICLE_ID_FW
), q as
(
Select VEHICLES_FW.LAST_INSPECTION_FW, JOB_HEADERS_FW_BY_VEHICLE_ID.FIELD2MAX NEW_LAST_INSPECTION_FW
FROM VEHICLES_FW
INNER JOIN JOB_HEADERS_FW_BY_VEHICLE_ID
ON VEHICLES_FW.VEHICLE_ID_FW = JOB_HEADERS_FW_BY_VEHICLE_ID.VEHICLE_ID_FW
INNER JOIN JOB_DETAILS_FW
ON JOB_NUMBER_FW = JOB_NUMBER_FW
WHERE REASON_CODE_FW = '35'
)
UPDATE q set LAST_INSPECTION_FW = NEW_LAST_INSPECTION_FW
I suspect this does what you want:
update v
set last_inspection_fw = (
select max(j.job_date_fw)
from job_headers_fw j
inner join job_details_fw jd on jd.job_number_fw = j.job_number_fw
where j.vehicle_id_fw = v.vehicle_id_fw and jd.reason_code_fw = 35
)
from vehicles_fw v

Update multiple rows with data from another table

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".

My UPDATE statement with WHERE EXISTS does not limit to the SELECT statement results

I have data in a temporary table and I am checking for duplicates in two other tables. I want to set a flag on the temp table (SET DupFlag = TRUE) for all duplicates found. My SELECT statement works perfectly, returning only the 48 duplicates that I entered to test with. But when I add UPDATE and WHERE EXISTS, every record in idTempImport2 is set to TRUE instead of just the 48 records returned from the SELECT statement. Is my syntax wrong? It looks like this:
UPDATE idTempImport2 as tmp2 SET DupFlag = TRUE
WHERE EXISTS
(SELECT * FROM idTempImport2 tmp2
LEFT JOIN (SELECT im.idDate, im.UserID, im.ActionID, im.IsHC, idn.Epic1, idn.Epic2
FROM idMain AS im
INNER JOIN idNotes AS idn ON im.aID = idn.MainID
WHERE idDate BETWEEN "2017-01-02" AND "2017-01-31") AS qry
ON qry.idDate = tmp2.idDate AND qry.UserID = tmp2.UserID AND qry.ActionID = tmp2.ActionID AND qry.Epic1 = clng(tmp2.Epic1) AND qry.Epic2 = clng(tmp2.Epic2)
WHERE qry.Epic1 <> NULL);
I think the ultimate issue is that you want a correlated subquery. As written, the subquery has no connection to the outer query, so it is likely that at least one row meets the condition. So, everything gets updated.
I think you intend:
UPDATE idTempImport2 as tmp2
SET DupFlag = TRUE
WHERE EXISTS (SELECT im.idDate, im.UserID, im.ActionID, im.IsHC, idn.Epic1, idn.Epic2
FROM idMain AS im INNER JOIN
idNotes AS idn
ON im.aID = idn.MainID
WHERE idDate BETWEEN "2017-01-02" AND "2017-01-31" AND
im.idDate = tmp2.idDate AND im.UserID = tmp2.UserID AND
im.ActionID = tmp2.ActionID AND
?.Epic1 = clng(tmp2.Epic1) AND ?.Epic2 = clng(tmp2.Epic2)
);

Subquery return more than one value

I have the following query which gives gives req_no and order_no. order_no is a from a sub_query which you can see from below sql. For a few req_no there are more than one order_no's and because of that I get ORA-01427: single-row subquery returns more than one row.
I would like to display both the order_no for one req_no, how can I achieve this?
Any help is highly appreciable.
Thanks
P.S. Our client's one database is still Oracle 8i.
SELECT max_qst.req_no,
(SELECT DISTINCT max_odr.order_no
FROM maximo_orders max_odr,
maximo_order_revisions max_odv,
maximo_order_items max_odi,
maximo_order_dates max_odd,
maximo_requisition_order max_rqo,
maximo_requisition_details max_req
WHERE max_req.req_no = max_qst.req_no
AND max_req.req_yr = max_qst.req_yr
AND max_odr.order_no = max_odi.order_no
AND max_odi.order_item_id = max_odd.order_item_id
AND max_req.requisition_item_id = max_rqo.requisition_item_id
AND max_rqo.order_schedule_id = max_odd.order_schedule_id
AND max_odv.order_no = max_odi.order_no
AND max_odv.revision_no =
(SELECT MAX (max_alias.revision_no)
FROM maximo_order_revisions max_alias
WHERE max_alias.order_no = max_odv.order_no)
AND maximo_order_item (max_odi.order_no,
max_odv.revision_no,
max_odi.order_item_id
) = 'CONFIRMED'
)
FROM maximo_requisitions max_qst, maximo_requisition_details max_qsd
WHERE max_qst.qst_id = max_qsd.qst_id
AND max_qst.enter_date = '2001'
AND max_qst.req_no = 'PUR_12WX'
Update 1
Desired out put.
REQ_No ORDER_NO
PUR_12WX PR_9078
PUR_12WX PR_9079
Use a join instead of a correlated sub-query.
I've removed the max_qst references from the sub-query and moved them to the join predicate.
I've also just changed it to use a LEFT JOIN. This allows for the possibility of there being no order_no values returned.
SELECT
max_qst.req_no,
sub_query.order_no
FROM
maximo_requisitions max_qst
INNER JOIN
maximo_requisition_details max_qsd
ON max_qst.qst_id = max_qsd.qst_id
LEFT JOIN
(
SELECT DISTINCT
max_odr.order_no,
max_req.req_no,
max_req.req_yr
FROM
maximo_orders max_odr,
maximo_order_revisions max_odv,
maximo_order_items max_odi,
maximo_order_dates max_odd,
maximo_requisition_order max_rqo,
maximo_requisition_details max_req
WHERE
max_odr.order_no = max_odi.order_no
AND max_odi.order_item_id = max_odd.order_item_id
AND max_req.requisition_item_id = max_rqo.requisition_item_id
AND max_rqo.order_schedule_id = max_odd.order_schedule_id
AND max_odv.order_no = max_odi.order_no
AND max_odv.revision_no = (SELECT MAX (max_alias.revision_no)
FROM maximo_order_revisions max_alias
WHERE max_alias.order_no = max_odv.order_no)
AND maximo_order_item (max_odi.order_no, max_odv.revision_no, max_odi.order_item_id) = 'CONFIRMED'
)
suq_query
ON max_qst.req_no = sub_query.req_no
AND max_qst.req_yr = sub_query.req_yr
WHERE
max_qst.enter_date = '2001'
max_qst.req_no = 'PUR_12WX'
You can use
DISTINCT
or
WHERE ROWNUM = 1
But I'd suggest you investigate why you're getting more than one row returned: Have you misunderstood the data, have you missed a join, is there erroneous or duplicate data etc etc.

SQL Server: UPDATE statement where MAX query

I'm doing a data migration in SQL Server 2008 R2. I'm a SQL-Server noob, but I know Ingres and MySql pretty well.
I need to set "default values" for two new fields to "the current values" from another table. Here's my first naive attempt (how I'd do it in Ingres).
update rk_risk
set n_target_probability_ID = a.n_probability_ID
, n_target_consequence_ID = a.n_consequence_ID
from rk_assess a
WHERE a.n_assess_id = (
SELECT MAX(n_assess_id)
FROM rk_assess a2
WHERE a2.n_risk_id = a.n_risk_id
);
The above query executes without error in sequel, but it sets ALL the n_target_probability_ID's & n_target_consequence_ID's to the same value... that of the OUTRIGHT last assessment (as apposed to "the last assessment OF THIS RISK").
The rk_assess table contains a complete history of assessment records for rk_risks, and my mission is to "default" the new target probability & consequence column of the risk table to the values from "the current" (i.e. the last) assessment record. The rk_assess.n_assess_id column is an auto-incremented identifier (immutable once set), so the max-id should allways be the last-entered record.
I've had a bit of a search, both in google and SO, and tried a few different version of the query, but I'm still stuck. Here's a couple of other epic-fails, with references.
update rk_risk
set n_target_probability_ID = (select a.n_probability_ID from rk_assess a where a.n_assess_id = (select max(n_assess_id) from rk_assess a2 where a2.n_risk_id = a.n_risk_id) as ca)
, n_target_consequence_ID = (select a.n_consequence_ID from rk_assess a where a.n_assess_id = (select max(n_assess_id) from rk_assess a2 where a2.n_risk_id = a.n_risk_id) as ca)
;
http://stackoverflow.com/questions/6256844/sql-server-update-from-select
update r
set r.n_target_probability_ID = ca.n_probability_ID
, r.n_target_consequence_ID = ca.n_consequence_ID
from rk_risk r
join rk_assess a
on a.n_risk_id = r.n_risk_id
select r.n_risk_id
, r.n_target_probability_ID, r.n_target_consequence_ID
, ca.n_probability_ID, ca.n_consequence_ID
from rk_risk r
join rk_assess a
on a.n_risk_id = r.n_risk_id
http://stackoverflow.com/questions/4024489/sql-server-max-statement-returns-multiple-results
UPDATE rk_risk
SET n_target_probability_ID = ca.n_probability_ID
, n_target_consequence_ID = ca.n_consequence_ID
FROM ( rk_assess a
INNER JOIN (
SELECT MAX(a2.n_assess_id)
FROM rk_assess a2
WHERE a2.n_risk_id = a.n_risk_id
) ca -- current assessment
Any pointers would be greatly appreciated. Thank you all in advance, for even reading this far.
Cheers. Keith.
How about this:
update rk_risk
set n_target_probability_ID = a.n_probability_ID
, n_target_consequence_ID = a.n_consequence_ID
from rk_assess a
JOIN (
SELECT n_risk_id, MAX(n_assess_id) max_n_assess_id
FROM rk_assess
GROUP BY n_risk_id
) b
ON a.n_risk_id = b.n_risk_id AND a.n_assess_id = b.max_n_assess_id
WHERE a.n_risk_id = rk_risk.n_risk_id
if you're using sql 2005 or greater you can in addition to Jerad's answer use the row_number function
With b
(
SELECT n_risk_id,
n_assess_id,
n_probability_ID,
n_consequence_ID,
row_number() over (partition by n_risk_id order by n_assess_id desc) row
FROM rk_assess
)
update rk_risk
set n_target_probability_ID = b.n_probability_ID
, n_target_consequence_ID = b.n_consequence_ID
from b
WHERE a.n_risk_id = rk_risk.n_assess_id
and row =1
Or CROSS JOIN
update rk_risk
set n_target_probability_ID = b.n_probability_ID
, n_target_consequence_ID = b.n_consequence_ID
from rh_risk r
CROSS JOIN
(
SELECT TOP 1
n_risk_id,
n_assess_id,
n_probability_ID,
n_consequence_ID
FROM rk_assess
order by n_assess_id desc
WHERE a.n_risk_id = r.n_assess_id) b
I tried this, looks like it is working:
update rk_risk
set n_target_probability_ID = a.n_probability_ID,
n_target_consequence_ID = a.n_consequence_ID
from rk_assess a, rk_risk r
WHERE a.n_risk_id = r.n_risk_id
and a.n_assess_id in (select MAX(n_assess_id) from rk_assess group by n_risk_id)
I discovered this from another question on SO just today. The UPDATE-FROM construction is not standard SQL, and MySQL's non-standard version is different from Postgres's non-standard version. From the problem here, it looks like SQL Server follows Postgres.
The problem, as Jerad points out in his edit, is that there is no link between the table being updated and the tables in the subquery. MySQL seems to create some implicit join here (on column names? in the other SO example, it was by treating two copies of the same table as the same, not separate).
I don't know if SQL Server allows windowing in the subquery, but if it does, I think you want
UPDATE rk_risk
set n_target_probability_ID = a.n_probability_ID
, n_target_consequence_ID = a.n_consequence_ID
from
( SELECT * FROM
( SELECT n_risk_id, n_probability_ID, n_consequence_ID,
row_number() OVER (PARTITION BY n_risk_id ORDER BY n_assess_ID DESC) AS rn
FROM rk_assess)
WHERE rn = 1) AS a
WHERE a.n_risk_id=rk_risk.n_risk_id;