Oracle SQL: pick the right values for an update - sql

I have two tables. One contains a list of tickets, one contains all the comments made in each ticket. A ticket has an owner, the comment makers are tracked by their user_id.
I want to set the owners of the tickets to the users that make the first comment. The base of the script is this:
update incident inc
inner join incidentdescription incdes on
inc.inci_id = incdes.inci_id
set inc.owner_id=incdes.user_id;
However, each ticket has several comments. I can track the first comment by the incdes.creationdate. I need to have the oldest one. However, how can I make sure that at the set part, I pick the incdes.user_id from the oldest comment from each ticket?

You can try any one of this in Oracle
Normal Update
UPDATE
INCIDENT
SET
INCIDENT.OWNER_ID =
( SELECT
INCIDENTDESCRIPTION.USER_ID
FROM
INCIDENTDESCRIPTION
WHERE
INCIDENT.OWNER_ID = INCIDENTDESCRIPTION.USER_ID )
WHERE
EXISTS
(SELECT
INCIDENTDESCRIPTION.USER_ID
FROM
INCIDENTDESCRIPTION
WHERE
INCIDENT.OWNER_ID = INCIDENTDESCRIPTION.USER_ID);
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
INCIDENT.OWNER_ID AS OLD,
INCIDENTDESCRIPTION.USER_ID AS NEW
FROM
INCIDENT
INNER JOIN
INCIDENTDESCRIPTION
ON INCIDENT.INCI_ID = INCIDENTDESCRIPTION.INCI_ID) T
SET
T.OLD = T.NEW;
Using Merge
MERGE INTO
INCIDENT
USING
(SELECT
T1.ROWID AS RID,
T2.INCI_ID
FROM
INCIDENT T1
INNER JOIN
INCIDENTDESCRIPTION T2
ON INCIDENT.INCI_ID = INCIDENTDESCRIPTION.INCI_ID)
ON
( ROWID = RID )
WHEN MATCHED
THEN
UPDATE SET INCIDENT.INCI_ID = INCIDENTDESCRIPTION.INCI_ID;

Related

Join to grab only non-matching records SQL

I have some data which I'm trying to clean in order to run further analysis on. One of the columns in the table is called record_type, this can either be NEW or DEL. This means that initially a NEW record might be added but then a DEL record would come in later to say that particular record is now expired (NEW and DEL records would be matched on the record_id). However both the NEW and DEL record would stay in the data, it doesn't get deleted.
So what I had planned to do is to create two CTEs, one for DEL records only and one for NEW records only:
WITH deleted_rec AS(
SELECT *
FROM main_table
WHERE record_type = 'DEL'
)
, new_rec AS(
SELECT *
FROM main_table
WHERE record_type = 'NEW'
)
Then outer join on the record_id column in both the CTEs.
SELECT *
FROM new_rec
FULL OUTER JOIN deleted_rec ON deleted_rec.record_id = new_rec.record_id
The goal would have been for the output to only include records which haven't had a DEL record come in for that record_id so that way I can guarantee that all the type NEW records I have in my final table would not have had a DEL record come in for them at any point and they would therefore all be active. However, I had forgotten that FULL OUTER JOIN return everything rather than just what didn't match so is there a way to get around this to get my desired output?
I would just use a single query with exists logic:
SELECT *
FROM main_table t1
WHERE record_type = 'NEW' AND
NOT EXISTS (SELECT 1 FROM main_table t2
WHERE t2.id = t1.id AND t2.record_type = 'DEL');
In plain English, the above query says to find all records which are NEW which also do not have associated with the same id another record having DEL.

Update a flag only if ALL matching condition fails

I am trying to write a query in oracle to only update a flag based on below scenario :
Scenario :
A mctn_id is linked with multiple PRPR_ID and each PRPR_ID can have different addresses, I need to update flag as N in a table if ALL PRPR_ID addresses don't belong to config table address. If any of it belongs to config table address then it shouldn't update the flag as N.
I am using not exists in this case which is not working.
update prcb_enroll_tbl
set prov_flg ='N',
sys_insert_dtm = systimestamp
where tin_number in (select mctn_id
from cc_pr_prov prpr
inner join cc_pr_addr prad
on prpr.prpr_id = prad.prad_id
and not exists (select 1
from fsg_prcb_config config
where prad.prad_addr1 = config.config_value)
The above query is updating a flag even if only one of the addresses belongs to config table which is not the expected outcome.
This shoulds like not exists. Does this do what you want?
update prcb_enroll_tbl pe
set prov_flg ='N', sys_insert_dtm = systimestamp
where not exists (
select 1
from cc_pr_prov pr
inner join cc_pr_addr pa on pr.prpr_id = pz.prad_id
inner join fsg_prcb_config pc on pc.config_value = pa.prad_addr1
where ??.mctn_id = pe.tin_number
)
It is unclear which table column mctn_id comes from, so I used ???: you should replace it with the correct table alias.

Update a table based on a temporary table in oracle

I want to update a column of a table(national_id from Personal_info) based on a value of a temporary table(nationalid from Tmp_Tbl).
Below Two tables having a pk/fk relation with each other using cid,user_id.
Users(cid,user_name)
Personal_info(user_id,national_id)
Temporary table also have a relation to Users table using user_name which is unique.
Tmp_Tbl(user_name,nationalid)
As it is oracle , i don't want to use of update join and also not merge syntax as i have the solution already.i am looking for a simple update query to use.
In Oracle, you can do this using subqueries, but you need to be careful. You need a similar subquery in the set and the where:
UPDATE Personal p
SET national_id = (SELECT t.nationalid
FROM tmp_tbl t JOIN
users u
ON t.user_name = u.user_name
WHERE u.cid = p.user_id
)
WHERE EXISTS (SELECT 1
FROM tmp_tbl t JOIN
users u
ON t.user_name = u.user_name
WHERE u.cid = p.user_id
);
If you leave out the WHERE clause, you will erase the national_id of users that are not in the temp table.
This assumes that you just want to update values for existing users. If you want to both add new users and insert values, then the code is more complicated.

SQL Update using value from join table

I tried using this sql to update a new column in a table from a value in table that already exists.
update "PROMOTION" t1
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc
inner join "PROMOTION" on "PROMOTION"."ID" = poc."PROMOTION_ID"
What happened is that the first value of the join got replicated in all the subsequent entries. about a both tables. The original table has unique values all the values in the updated column are the same.
Eventually I used this SQL instead.
update "PROMOTION" t1
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc
where
t1."ID" = poc."PROMOTION_ID"
This update works and duplicates all the data, 1000 unique elements in the original table, 1000 unique elements in the updated table.
Is this a bug, or is this the expected result?
SQL is behaving correctly. Your original query is:
update "PROMOTION" t1
--------^
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc inner join
"PROMOTION"
-----------^
on "PROMOTION"."ID" = poc."PROMOTION_ID"
Note that the table PROMOTION is mentioned twice. Not good. So, the join takes place, producing lots of rows. Then there is no correlation to the t1 version of the table.
You don't mention the database you are using. In SQL Server, you would just do:
update p
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc inner join
"PROMOTION" p
on p."ID" = poc."PROMOTION_ID";
Note the alias is used after the update (or table name with if there is no alias). Now the table is mentioned only once, so the update should behave as desired.

Update database from another using joins?

I am trying to update a table from another database using joins and having a hard time. This is what I am trying to do in pseudo:
UPDATE [Database1].[dbo].[Sessions]
SET [SpeakerID] = ?STATEMENT1?
WHERE ?STATEMENT2?
For "Statement1", this would be coming from another database and table that has columns: SessionID and SpeakerID. How can this be achieved?
UPDATE a
SET a.SpeakerID = b.colName -- SET valoue here
FROM Database1.dbo.Sessions a
INNER JOIN Database2.dbo.Sessions b
ON a.SessionID = b.SessionID -- assumes that their
-- relationship column is SessionID,
-- change it in your original columnName
WHERE ....
a and b are called alias. They are useful when you have longer source name.
UPDATE L
SET SpeakerID = R.SpeakerID
FROM dbo.LocalTable AS L
INNER JOIN RemoteDatabase.dbo.RemoteTable AS R
ON L.SomeValue = R.SomeValue;
This really is no different from this problem except you have to add a database prefix to one of the tables in the join.
try
UPDATE [Database1].[dbo].[Sessions]
SET
Sessions.col1 = other_table.col1
FROM
[Database1].[dbo].[Sessions] Sessions
INNER JOIN
[Database2].[dbo].other_table AS other_table
ON
Sessions.id = other_table.id
WHERE Sessions.id = ??
Note if the database is on another server you will need to create a linked server first
http://msdn.microsoft.com/en-us/library/ff772782.aspx