Multiple SET in single UPDATE statement? - sql

I'm working on SQL Server, Oracle, DB2 Database.
Currently, I'm performing the below 2 update statement to update one table.
Update 1:
UPDATE TABLE1
SET COL1=TABLE2.ATTRIBUTE1,
COL2=TABLE2.ATTRIBUTE2,
COL3=TABLE2.ATTRIBUTE3
FROM TABLE1
INNER JOIN TABLE2
ON COL1=TABLE2.PID1
AND COL2=TABLE2.PID2
WHERE ROWNUM<10
Update 2:
UPDATE TABLE1
SET COL1=’123-4567890-1’,
COL2=’0000000000’,
COL3=’CONSTANT FULL NAME’
WHERE NOT EXISTS (SELECT 1 FROM TABLE2 WHERE COL1=TABLE2.PID1)
Update 1, helps to updates the TABLE1 if the values match with Table2 and
Update 2, helps to update the TABLE1 if the values, not match with Table2
Is there any other way to convert two update statement into single UPDATE statement?
NOTE: We can use MERGE also, but MERGE will update if the data matched and will insert if the data not matched.

To have one update, you can use two LEFT JOINs, one for each table join condition. And then, in SET part, you use CASE WHEN ... THEN ... END checking if the PK from related joins IS NULL.
Something like below
UPDATE TABLE1
SET COL1=CASE
WHEN T1.PID1 IS NOT NULL THEN T1.ATTRIBUTE1
WHEN T2.PID1 IS NULL THEN ’123-4567890-1’
ELSE COL1
END,
etc.
FROM TABLE1
LEFT JOIN TABLE2 T1 ON COL1=T1.PID1 AND COL2=T1.PID2 AND ROWNUM < 10
LEFT JOIN TABLE2 T2 ON CEDULA=T2.PID1
WHERE T2.PID1 IS NULL OR T1.PID1 IS NOT NULL
However, having one UPDATE statement doesn't mean it will be faster - check the query plan and actual performance.

Related

Update table if exist or insert if not

I have 2 SQL tables with same column label, Table1 and Table2.
I want to update Table1 with value of Table2 if there is a same value for an attribute.
The tables has CODE, POSITION, DESCRIPTION as columns.
I do this:
UPDATE Table1
SET CODE = Table2.CODE,
POSITION= Table2.POSITION
FROM Table2
WHERE DESCRIPTION = Table2.DESCRIPTION
It works, but if in the DESCRIPTION Value of Table2 is not present into Table1, I want to insert the entire row, in other words I need to do something like:
UPDATE IF DESCRIPTION EXISTS
ELSE INSERT
How can I do this?
You can do this from first-principals in 2 steps
Update the existing values like you have done:
UPDATE Table1
SET
CODE= t2.CODE,
POSITION= t2.POSITION
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.DESCRITPION = t2.DESCRITPION
Then you can insert the missing records
INSERT INTO Table1 (CODE, POSITION, DESCRITPION)
SELECT CODE, POSITION, DESCRITPION
FROM Table2 t2
WHERE NOT EXISTS (SELECT DESCRITPION
FROM Table1 t1
WHERE t1.DESCRITPION = t2.DESCRITPION)
Most RDBMS have a MERGE statement that allows you to combine these two queries into a single atomic operation, you'll need to check the documentation for your vendor, but an MS SQL Server MERGE solution looks like this:
MERGE INTO Table1 AS tgt
USING Table2 AS src
ON tgt.DESCRITPION = src.DESCRITPION
WHEN MATCHED
THEN UPDATE SET CODE= src.CODE,
POSITION= src.POSITION
WHEN NOT MATCHED THEN
INSERT (CODE, POSITION, DESCRITPION)
VALUES (src.CODE, src.POSITION, src.DESCRITPION)
An additional benefit to the MERGE clause is that it simplifies capturing the changed state into the OUTPUT clause which allows for some complex logic all while keeping the query as a single operation without having to manually create and track transaction scopes.

Merge into Table1 using table2, table3 on (multiple conditions)? Missing syntax

I have table1, table2 and table3,
they have a join condition that relates between them.
suppose it is the (ID) column.
So the question is,
in the case of using the merge statement, is it possible
to construct the syntax to be like this:
Merge into Table1
using table2 , table3
on (table1.ID = Table2.ID , Table2.ID = Table.ID)
when match then
update --(definitly table1)
where
table1.something between table2.something and table2.something -- whatever :)
when not match then
do_nothing --I think I should type NULL here
if this syntax is wrong, how should I call two tables and using them to update a row in table1?
how should I call two tables and using them to update a row in table1?
This can be achieved in several ways in Oracle :
correlated subquery
inline view
merge query
The following code gives a raw, commented example of the third solution (merge statement). As you did not show us your exact SQL attempt and the structure of your tables, you will have to adapt this to your exact use case :
MERGE INTO table1 target
-- prepare the dataset to use during the UPDATE
USING (
SELECT
-- following fields will be available in the UPDATE
t1.id,
t2.foo,
t3.bar
FROM
-- JOIN conditions between the 3 tables
table1 t1
INNER JOIN table2 t2 on t2.id = t1.id
INNER JOIN table3 t3 on t3.id = t1.id
WHERE
-- WHERE clause (if needed)
t1.zoo = 'blah'
) source
-- search records to UPDATE
ON (target.id = source.id)
WHEN MATCHED THEN
UPDATE SET
-- UPDATE table1 fieds
target.value1 = source.foo,
target.value2 = source.foo
;
Note : while this query makes use of the Oracle MERGE statement, it conceptually does not implement a real merge operation. The concept of a merge is an update/insert query, whereas this query only does an update, and ignores the insert part. Still, this is one of the simplest way to perform such a correlated update in Oracle...

ORA-01427 Subquery returns more then one row..Oracle Update Statement

How do you write a update statement with a Sub-Select in an Oracle Environment (SQL Developer)?
Example: UPDATE table SET column = (SELECT....)
Every time I try this it gives me ORA-01427 "Sub select returns more then one row" even if there is no WHERE clause..
Based on the understanding of your question I'd suggest use Merge statement.
Merge into Table1
Using
(SELECT * from table2 where condition) Temp
On (Table1.columname condition Temp.columname)
When matched Then update Set Table1.column_name = Temp.column_name;
Table1 is the table where you want to update the records.
Table2 is the table from which you want to get the data (The sub query which you are talking about )
Using this merge statement you will be able to update n number of rows.
If you want to update multiple rows, you can either use a MERGE statement (as in #jackkds7's answer above) or you can use a filter on your subselect:
UPDATE table t1
SET column = ( SELECT column FROM table2 t2 WHERE t2.key = t1.key );
If there aren't matches in table2 for all the records in table then column will be set to NULL for the non-matches. To avoid that, add a WHERE EXISTS clause:
UPDATE table t1
SET column = ( SELECT column FROM table2 t2 WHERE t2.key = t1.key )
WHERE EXISTS ( SELECT 1 FROM table2 t2 WHERE t2.key = t1.key );
Oh and in the event that key is not unique for table2, you can aggregate (up to you to figure out which function would be best):
UPDATE table t1
SET column = ( SELECT MAX(column) FROM table2 t2 WHERE t2.key = t1.key )
WHERE EXISTS ( SELECT 1 FROM table2 t2 WHERE t2.key = t1.key );
Hope this helps.
I think it would help if you posted your actual query.
In essence, the "inner" select would be executed for each row that would be updated. This inner select query is called a correlated subquery:
UPDATE table t SET t.column = (
select ot.othercolumn from othertable ot
where ot.fk = t.id --This is the correlation part, that finds
--he right value for the row you are currently updating
)
You must ensure the subquery you use will always return just a single row and a single column for every time it runs (that is, for every row that is going to be updated). If needed, you can use MAX(), or ROWNUM to ensure you always only get 1 value
More examples:
Using Correlated Subqueries

How to select a value that can come from two different tables?

First, SQL is not my strength. So I need help with the following problem. I'll simplify the table contents to describe the problem.
Let's start with three tables : table1 with columns id_1 and value, table2 with columns id_2 and value, and table3 with columns id_3 and value. As you'll notice, a field value appears in all three tables, while ids have different column names. Modifying column names is not an option because they are used by Java legacy code.
I need to set table3.value using table1.value or table2.value according to the fields table1.id_1, table2.id_2 and table3.id_3.
My last attempt, which describes what I try to do, is the following:
UPDATE table3
SET value=(IF ((SELECT COUNT(\*) FROM table1 t1 WHERE t1.id_1=id_3) > 0)
SELECT value FROM table1 t1 WHERE t1.id_1=id_3
ELSE IF ((SELECT COUNT(\*) FROM table2 t2 WHERE t2.id_2=id_3)) > 0)
SELECT value FROM table2 t2 WHERE t2.id_2=id_3)
Here are some informations about the tables and the update.
This update will be included in an XML file used by Liquibase.
It must work with Oracle or SQL Server.
An id from table3.id_3 can be found at most once in table1.id_1 or in table2.id_2, but not in both tables simultaneously.
If table3.id_3 is not found in table1.id_1 nor in table2.id_2, table3.value remains null.
As you can imagine, my last attempt failed. In that case, the IF command was not recognized during the Liquibase update. If anyone has any ideas how to deal with this, I'd appreciate. Thanks in advance.
I don't know Oracle very well, but a SQL Server approach would be the following using COALESCE() and OUTER JOINs.
Update T3
Set Value = Coalesce(T1.Value, T2.Value)
From Table3 T3
Left Join Table2 T2 On T3.Id_3 = T2.Id_2
Left Join Table1 T1 On T3.Id_3 = T1.Id_1
The COALESCE() will return the first non-NULL value from the LEFT JOIN to tables 1 and 2, and if a record was not found in either, it would be set to NULL.
It is Siyual's UPDATE written with MERGE operator.
MERGE into table_1
USING (
SELECT COALESCE(t2.value, t3.value) as value, t1.id_1 as id
FROM table_1 t1, table_2 t2, table_3 t3
WHERE t2.id_2 = t3.id_3 and t1.id_1 = t2.id_2
) t on (table_1.id_1 = t.id)
WHEN MATCHED THEN
UPDATE SET table_1.value = t.value
This should work in Oracle.
In Oracle
UPDATE table3 t
SET value=COALESCE((SELECT value FROM table1 t1 WHERE t1.id_1=t.id_3),
(SELECT value FROM table2 t2 WHERE t2.id_2=t.id_3))
Given your assumption #3, you can use union all to put together tables 1 and 2 without running the risk of duplicating information (at least for the id's of interest). So a simple merge solution like the one below should work (in all DB products that implement the merge operation).
merge into table3
using (
select id_2 as id, value from table2
union all
select id_3, value from table 3
) t
on table3.id_3 = t.id
when matched
then update set table3.value = t.value;
You may want to test the various solutions and see which is most effective for your specific tables.
(Note: merge should be more efficient than the update solution using coalesce, at least when relatively few of the id's in table3 have a match in the other tables. This is because the update solution will re-insert NULL where NULL was already stored when there is no match. The merge solution avoids this unnecessary activity.)

UPDATE statement with WHERE calsue from 2 tables

looking for some advice on how to perform an update to a table, but where my 2 WHERE statements come from different tables. Here's what I'm thinking:
UPDATE table1
SET table1.t1field=('new parameter');
FROM table1
WHERE table1.t1field > ('parameter')
INNER JOIN
table 2
ON table2.t2field = ('my other parameter');
Basically, what I want to do is update X, where X = myparameter (from table 1) and myparameter2 (from table 2).
Am I getting the syntax right? If I take out the semi-colon after the new parameter, I get a "SQL command not properly ended" error, but with it left in, I think it's trying to update everything in the table! Obviously I don't want this, I only want it tp update that paramater if it meets the 2 criteria.
Thanks for any help you can give.
It should be something like following:
UPDATE table1
INNER JOIN table2
ON table2.join_field = table1.join_field
SET table1.t1field=('new parameter'), table2.t2field = ('my other parameter')
FROM table1
WHERE table1.t1field > ('parameter');
The correct syntax for update queries with join is the following:
UPDATE t1
SET t1.[column]=[value]
FROM table1 t1 INNER JOIN table2 t2 ON [join condition]
WHERE [conditions]