Table update based on match/nomatch - sql

I have two tables t1 and t2.
t1 has this structure:
yearmonth
account
company
RCV_amount_t1
t2 has this structure:
yearmonth
account
company
billing amount
billing amount CM_1
billing amount CM_2
RCV_amount_t2
I want to join t2 to t1 using yearmonth, account, and company. If they match, I want to update RCV_amount_t2 with the value in RCG_amount_t1. Otherwise, I want to set RCV_amount_t2 to spaces.
In the same manner, I want to join t1 with t2 using yearmonth, account, and company and set values accordingly.
Is it possible to achieve? If so, how do I go about it?

I want to join t2 to t1 using yearmonth, account, and company. If they
match, I want to update RCV_amount_t2 with the value in RCG_amount_t1.
Otherwise, I want to set RCV_amount_t2 to spaces.
This will update the matching rows with the appropriate value, and update the rows with no match to NULL. If the field is numeric, you can't update it to "spaces"; NULL would be the appropriate indicator of no value. If the field is not numeric, then you could do a second update to replace NULL values with whatever you like, but NULL would still seem to me to be the most appropriate indicator of no value.
UPDATE t2 SET rcv_amount_t2 = (
SELECT rcv_amount_t1
FROM t1
WHERE t1.yearmonth = t2.yearmonth
AND t1.account = t2.account
AND t1.company = t2.company
)

You'll want to use a MERGE.
It allows you to join two tables and specify how to update the values if they match.
The general structure of a MERGE statement looks like:
MERGE INTO driver_table
USING other_table
ON
(
driver_table.column1 = other_table.column1
AND driver_table.column2 = other_table.column2
AND ...
)
WHEN MATCHED THEN UPDATE
SET
driver_table.some_column = other_table.some_value,
driver_table.some_flag = 'Y',
...
;

It seems that we cannot resolve it in a single query, we need a merge and a correlated query, It works fine for me:
This will update t2 with values from t1 when matched:
MERGE INTO t2
USING (SELECT yearmonth, account, company, RCV_amount_t1 FROM t1) S
ON (t1.yearmonth = t2.yearmonth and
t1.account = t2.account and
t1.company = t2.company)
WHEN MATCHED THEN UPDATE SET t2.RCV_amount_t2 = S.RCV_amount_t1;
Then a query containg a corrolated subquery to blank when not matched:
update t2 set RCV_amount_t2 = ' ' where yearmonth||account||company not in(
select yearmonth||account||company from t1
where t1.yearmonth = t2.yearmonth and t1.account=t2.account and t1.company=t2.company);

Related

SQL UPDATE table1 row-by-row based on values in table2

I have two tables and I want to UPDATE one table based on the values of another table.
With the help of the following SO-post I write a query:
query = f""" UPDATE table1
SET goal =
(SELECT table2.goal FROM table2
WHERE player = table2.player
AND opponent = table2.opponent
AND date = table2.date
AND competition = table2.competition
AND score = table2.score """
When I execute the query every row of table1 is affected with the same value for goal. However, the desired process is that the query checks row-by-row if there are matching rows and, if so, update the column goal. What am I doing wrong?
You must correlate the subquery with the table that you want to update:
UPDATE table1 AS t1
SET goal = (
SELECT t2.goal
FROM table2 AS t2
WHERE t2.player = t1.player
AND t2.opponent = t1.opponent
AND t2.date = t1.date
AND t2.competition = t1.competition
AND t2.score = t1.score
);
Or:
UPDATE table1 AS t1
SET goal = (
SELECT t2.goal
FROM table2 AS t2
WHERE (t2.player, t2.opponent, t2.date, t2.competition, t2.score) =
(t1.player, t1.opponent, t1.date, t1.competition, t1.score)
);
Note that if a row in table1 does not match any row in table2, the column will be updated to null.
If in this case you don't want the column to be updated use also COALESCE():
UPDATE table1 AS t1
SET goal = COALESCE((
SELECT t2.goal
FROM table2 AS t2
WHERE (t2.player, t2.opponent, t2.date, t2.competition, t2.score) =
(t1.player, t1.opponent, t1.date, t1.competition, t1.score)
), goal);
If your version of SQLite is 3.33.0+, you could use the UPDATE..FROM syntax:
UPDATE table1 AS t1
SET goal = t2.goal
FROM table2 AS t2
WHERE (t2.player, t2.opponent, t2.date, t2.competition, t2.score) =
(t1.player, t1.opponent, t1.date, t1.competition, t1.score);
From what I understand, this query will only affect the table1 if the table2 have the same values. Do you want to check if any row is the same then update the goal value?
Instead of using AND, you could use OR. This modification will make sure the query will go through if any of the values are similar.
query = f""" UPDATE table1
SET goal =
(SELECT table2.goal FROM table2
WHERE player = table2.player
OR opponent = table2.opponent
OR date = table2.date
OR competition = table2.competition
OR score = table2.score )"""

Updating to another Database with a lengthy IN clause

I'm trying to update certain columns from one DB to another in tables whose Id columns align.
I have the query below, but I fear it will update all rows because the IN clause values aren't being matched.
How do I match all those values within the IN clause to the relevant column from Table1? Or is this correct as is?
UPDATE Table1
SET NAME = T2.Name
FROM OTHERDB.[Table2] as T2
WHERE T2.Id in
(
'12345678'
--...
}
Your suspicions are correct: your query will update every row.
You need a join:
UPDATE T1
SET NAME = T2.Name
FROM Table1 T1
JOIN OTHERDB.Table2 as T2 ON T2.Id = T1.Id
WHERE T1.Id in (
'12345678',
...
}
This assumes that Id columns match up between databases. If that’s not the case, the join/where clauses would need adjustment.
Using an inner join means if there’s no corresponding data in the other database, there won’t be an update to null.
The where clause now looks up on the local table’s Id for efficiency.
You can try the following:
UPDATE Table1
SET Table1.Name = T2.Name
FROM OtherDB.Table2 T2
WHERE T2.Id IN
(
SELECT Id FROM Table1 (NOLOCK) WHERE ...
)

Setting a value in one table depending on count of entries in other table

So I am fairly new to working with databases so my apologies in advance if this is an obvious one.
I have following issue. In my Database I have two tables with entries. In Table1 there are entries which all have an ID and a field in which there is a counter. In Table2 there are entries which have a fied with an ID out of Table1 as foreign key (fk_table1_id).
My Goal is to set the counter for each entry in table1 to the number of entries in table2 that have fk_table_id of the entry from table1.
So basically I thought of something like this (pseudocode)
foreach (entries of table1 as entry$entry) {
update `table1` where `id` = `entry->id` set `count`= {
count `table2`wehere `fk_table1_id` = entry->id
}
}
thanks in advance.
You can use join with an aggregation subquery:
update table1 t1 join
(select fk_table1_id, count(*) as cnt
from table2 t2
group by fk_table1_id
) t2
on t2.fk_table1_id = t1.id
set t1.count = t2.cnt;
Note: This only sets counts where rows exist in the second table. If you want 0 counts, then:
update table1 t1 left join
(select fk_table1_id, count(*) as cnt
from table2 t2
group by fk_table1_id
) t2
on t2.fk_table1_id = t1.id
set t1.count = coalesce(t2.cnt, 0);

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

SQL Server update statement using a join on multiple columns

Having some trouble here.
Table 1:
CID, Name, HID
(001-233, Test1, 12345)
Table 2:
CID, Name, HID, Primary
(001-233, Test1, 12345, '')
Want to update Table2 where a join exists with Table1 with a constant value called 'Y'
So statement is as follows:
UPDATE T2 SET T2.Primary = 'Y'
FROM T2
INNER JOIN T1
ON (T1.CID = T2.CID
AND T1.HID = T2.HID)
This statement just ends up updating all the rows, it's like it only does a join on one id and not the other? I finally gave up and did a WHERE IN subquery with a single "id" by concatenating the two ide fields CID+HID. But I want to understand why this didnt work using the proper join.
Table1 is a CTE..
update t2
set (t2.primary) = (select 'Y' from t1 where T1.CID = T2.CID AND T1.HID = T2.HID)