I am trying to update a key on a table (t1) when the key value is (abc) by getting the value from table (t2).
It is working as expected when I am limiting it to a specific person
update table_a t1
set t1.u_key = (select t2.u_key
from table_b t2
where t2.name_f=t1.name_f
and t2.name_l=t1.name_l
and rownum<=1
and t2='NEVADA')
where t1.u_key = 'abc'
and e.name_f='Lori'
and e.name_l='U'
;
I initially tried without rownum and it said too many rows returned.
To run on all the data with t1.u_key='abc' and took out the specific name, I tried this which has been running until time out.
update table_a t1
set t1.u_key = (select t2.u_key
from table_b t2
where t2.name_f=t1.name_f
and t2.name_l=t1.name_l
and rownum<=1
and t2='NEVADA')
where t1.u_key = 'abc'
;
Can you please look at it and suggest what am I missing.
You should first take a look what is returned when you run the inner SELECT statement alone:
SELECT t2.u_key FROM table_b t2
WHERE t2.name_f IN (SELECT name_f FROM table_a WHERE u_key = 'abc')
AND t2.name_l IN (SELECT name_l FROM table_a WHERE u_key = 'abc')
AND t2='NEVADA'
Examine the results and you will see that there are more than one row returned.
If there should be only matching row per key, you would need to add the key to the inner SELECT as well but I can't tell you how it should look like without additional table descriptions and possibly some sample entries from table_a and table_b.
Use this:
update (
SELECT t2.u_key t2key,
t1.ukey t1key
FROM table_b t2,
table_a t1
where t2.name_f=t1.name_f
and t2.name_l=t1.name_l
and t2='NEVADA'
and rownum<=1 )
SET t1key = t2key
where t1key = 'abc';
merge into table_a t1
using(
select name_f, name_l, max(u_key) as new_key
from table_b t2
where t2='NEVADA'
group by name_f, name_l
) t2
on (t1.name_f=t2.name_f and t1.name_l=t2.name_l and t1.u_key='abc')
when matched then
update set t1.u_key=t2.new_key
Related
I have two tables T1,T2 I have to add the column id of T1 in T2 and update a value in T1.
So I am able to get the values from T2 using RETURNING,but when using values in UPDATE WHERE then not able to UPDATE the column
Example:
WITH "T1S" AS (INSERT INTO "T1" VALUES()RETURNING id AS "T1id" ),
"T2S" AS (INSERT INTO "T2"(t1_id) VALUES(
(SELECT "T1id" FROM "T1S"))
)RETURNING t1_id AS "T1id",t2_id AS "T2id"
)
UPDATE "T1" set value=t2_id WHERE id IN (SELECT t1_id FROM "T2S")
Image of query
If I understand correctly, this is the logic that you want:
WITH T1S AS (
INSERT INTO "T1"
VALUES ()
RETURNING id AS T1id
),
T2S AS (
INSERT INTO "T2" (t1_id)
SELECT T1ID
FROM T1S
RETURNING *
)
UPDATE "T1" t1
SET value = T2S.t2_id
FROM T2S
WHERE t1.id = T2S.t1_id;
Notes:
Using double quotes for table and column names is a bad practice. Using them for CTEs and column aliases is an absurdity. They just make references harder.
The solution is that you want the join the table to the CTE in the final UPDATE.
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
I am trying to perform a merge into a table (let's call it table1) from a table2. In the USING condition I need a third table (table3). This third table contains some IDs that I need in table1. A simplified version of my merge looks like:
MERGE INTO table1 a
USING (
SELECT ID, address
FROM table3 b
Where address IN
(
SELECT address
FROM table3
WHERE address IS NOT NULL
AND ID> 0
GROUP BY address
HAVING COUNT(*) = 1
)
) c
ON (a.address = c.address)
WHEN MATCHED THEN
UPDATE SET a.ID = c.ID
WHERE a.ID = 0
I know that the error I get is usually caused by the query in the USING clause, but theoretically this problem should be eliminated by the count(*)=1 condition.
I have duplicates in table2, but they should all get an ID from table3 or ID 0 if the address is duplicated in table3.
IDs are unique for an address, so they should be distinct.
P.S. This merge is performed automatically by a script that , so I can modify the query to add more conditions/restrictions, but I cannot change the structure [meaning I have to use these 3 tables as they are].
I hope this makes sense.
Any ideas why this still does not work for me?
Try this:
MERGE INTO table1 a
USING (
SELECT max(ID), address
FROM table3 b
WHERE address IS NOT NULL AND ID > 0
GROUP BY address
HAVING COUNT(*) = 1
) c
ON (a.address = c.address)
WHEN MATCHED THEN
UPDATE SET a.ID = c.ID
WHERE a.ID = 0;
you have where condition in inner query but not in outer query. If you want your original query please try:
MERGE INTO table1 a
USING (
SELECT ID, address
FROM table3 b
AND address IN
(
SELECT address
FROM table3
WHERE address IS NOT NULL
AND ID> 0
GROUP BY address
HAVING COUNT(*) = 1
)
WHERE address IS NOT NULL
AND ID> 0
) c
ON (a.address = c.address)
WHEN MATCHED THEN
UPDATE SET a.ID = c.ID
WHERE a.ID = 0
The issue is more than likely due to the duplicate rows from table2. Here's a simple test case demonstrating the issue:
Setup:
CREATE TABLE t1 (ID INTEGER PRIMARY KEY,
val VARCHAR2(1));
CREATE TABLE t2 (ID INTEGER,
val VARCHAR2(1));
INSERT INTO t1 (ID, val) VALUES (1, 'A');
INSERT INTO t2 (ID, val) VALUES (1, 'B');
INSERT INTO t2 (ID, val) VALUES (1, 'B');
COMMIT;
Merge that will error:
MERGE INTO t1 USING t2
ON (t1.id = t2.id)
WHEN MATCHED THEN
UPDATE SET t1.val = t2.val;
ORA-30926: unable to get a stable set of rows in the source tables
Merge that will succeed:
MERGE INTO t1 USING (SELECT DISTINCT id, val FROM t2) t2
ON (t1.id = t2.id)
WHEN MATCHED THEN
UPDATE SET t1.val = t2.val;
N.B. The second merge will still fail if you have different values returned for val for the same id; that means you will have more than one row returned for a given id, and Oracle won't know which one to use to update the target table with.
In order to make sure your merge statement will work, you will need to ensure that you will return at most 1 row per address in the source subquery.
I have two tables, with a same column named user_name, saying table_a, table_b.
I want to, copy from table_b, column_b_1, column_b2, to table_b1, column_a_1, column_a_2, respectively, where the user_name is the same, how to do it in SQL statement?
As long as you have suitable indexes in place this should work alright:
UPDATE table_a
SET
column_a_1 = (SELECT table_b.column_b_1
FROM table_b
WHERE table_b.user_name = table_a.user_name )
, column_a_2 = (SELECT table_b.column_b_2
FROM table_b
WHERE table_b.user_name = table_a.user_name )
WHERE
EXISTS (
SELECT *
FROM table_b
WHERE table_b.user_name = table_a.user_name
)
UPDATE in sqlite3 did not support a FROM clause for a long time, which made this a little more work than in other RDBMS. UPDATE FROM was implemented in SQLite 3.33 however (2020-08-14) as mentioned at: https://stackoverflow.com/a/63079219/895245
If performance is not satisfactory, another option might be to build up new rows for table_a using a select and join with table_a into a temporary table. Then delete the data from table_a and repopulate from the temporary.
Starting from the sqlite version 3.15 the syntax for UPDATE admits a column-name-list
in the SET part so the query can be written as
UPDATE table_a
SET
(column_a_1, column_a_2) = (SELECT table_b.column_b_1, table_b.column_b_2
FROM table_b
WHERE table_b.user_name = table_a.user_name )
which is not only shorter but also faster
the last "WHERE EXISTS" part
WHERE
EXISTS (
SELECT *
FROM table_b
WHERE table_b.user_name = table_a.user_name
)
is actually not necessary
It could be achieved using UPDATE FROM syntax:
UPDATE table_a
SET column_a_1 = table_b.column_b_1
,column_a_2 = table_b.column_b_2
FROM table_b
WHERE table_b.user_name = table_a.user_name;
Alternatively:
UPDATE table_a
SET (column_a_1, column_a_2) = (table_b.column_b_1, table_b.column_b_2)
FROM table_b
WHERE table_b.user_name = table_a.user_name;
UPDATE FROM - SQLite version 3.33.0
The UPDATE-FROM idea is an extension to SQL that allows an UPDATE statement to be driven by other tables in the database. The "target" table is the specific table that is being updated. With UPDATE-FROM you can join the target table against other tables in the database in order to help compute which rows need updating and what the new values should be on those rows
There is an even much better solution to update one table from another table:
;WITH a AS
(
SELECT
song_id,
artist_id
FROM
online_performance
)
UPDATE record_performance
SET
op_song_id=(SELECT song_id FROM a),
op_artist_id=(SELECT artist_id FROM a)
;
Update tbl1
Set field1 = values
field2 = values
Where primary key in tbl1 IN ( select tbl2.primary key in tbl1
From tbl2
Where tbl2.primary key in tbl1 =
values);
The accepted answer was very slow for me, which is in contrast to the following:
CREATE TEMPORARY TABLE t1 AS SELECT c_new AS c1, table_a.c2 AS c2 FROM table_b INNER JOIN table_a ON table_b.c=table_a.c1;
CREATE TEMPORARY TABLE t2 AS SELECT t1.c1 AS c1, c_new AS c2 FROM table_b INNER JOIN t1 ON table_b.c=t1.c2;
I need to write an SQL script that selects one record in table1, then does a lookup in the remaining tables in the database. If it doesn't find the record, I need delete the record from table1. Anyone provide some sample script?
One example
delete table1
where not exists (select 1
from Table2
where table1.SomeColumn = Table2.SomeColumn)
AND table1.SomeColumn = 5 --just an example,
Leave the AND out if you want to delete all the rows from table 1 that do not exist in table 2
you can also use LEFT JOIN or NOT IN
I have done things like this:
DELETE table1
FROM table1
WHERE table1.ID NOT IN (
SELECT RefID FROM Table2
UNION
SELECT RefID FROM Table3
...
)
Assuming RefID are FK's to table1.ID. Is this what you need?
DELETE FROM Table1 WHERE id=10 AND NOT EXISTS (SELECT * FROM Table2 WHERE id=10);
Very generally, (since you gave little details)
Delete Table1 t1
Where [Criteria to find table1 Record]
And Not Exists(Select * From Table2
Where pk = t1.Pk)
And Not Exists(Select * From Table3
Where pk = t1.Pk)
And Not Exists(Select * From Table4
Where pk = t1.Pk)
... etc. for all other tables