I want to insert a row in a DB based on following codition
if table t has doesnot not have row with key X:
insert into t mystuff..
else
if update t set mystuff... where mykey=X if existingversion < NewVersion
I know that normal merge can be used as follows
MERGE INTO (SELECT * FROM mytable WHERE status='active') old
USING (SELECT * FROM newtable) new
ON (new.id = old.id)
WHEN MATCHED THEN UPDATE SET old.data1=new.data1;
But how do i handle my conditional update of my merge ?
You could filter the rows you want to upsert, for instance:
MERGE INTO (SELECT * FROM mytable WHERE status='active') old
USING (SELECT *
FROM newtable n
WHERE NOT EXISTS (SELECT NULL
FROM mytable m
WHERE m.id = n.id
AND m.version >= n.version) new
ON (new.id = old.id)
WHEN MATCHED THEN UPDATE SET old.data1=new.data1;
Related
I'm running a merge statement but I want the update to happen only if there is exactly one row matching.
merge into mergetest using dual on (a = 1)
when matched then update set b = b+1;
I know I can include a where clause at the end, but I have no idea what to do. Group functions are not allowed, so count(*) = 1 doesn't work.
Does this work?
merge into mergetest
using (select a, count(*) as cnt
from mergetest
where a = 1
group by a
) mt
on mergetest.a = mt.a and cnt = 1
when matched then
update set b = b + 1;
In PL/SQL this could be solved in the following way:
select count(*) into l_count from mergetest where a = 1;
case l_count
when 0 then
insert into mergetest (a,b) values (1,1);
when 1 then
update mergetest set b = b + 1 where a = 1;
else
NULL;
end case;
I need your advice to my below case.
I get data from maintable and insert into dataTable where rownum <= some value
once all data already insert into datatable, i want this data in maintable will update the staus.
The problem is if the rownum more than 500k, it take about 10 minutes. This time there could be another request was pickup the same data. How i want to prevent this?
Below is my sql.
insert into dataTable(id,num,status) select m.id,m.num,m.status from mainTable m where m.status = 'FREE' and rownum <= 100000;
update mainTable m set m.status = 'RESERVED' where m.num in (select d.num from dataTable where d.status = 'FREE');
I do some research, but i dont know whether i need to use the select for update or merge statement?
You can't use MERGE, as you can only insert into or update the target table. I would guess that the problem is either the selectivity of the column STATUS in dataTable or of the column NUM in mainTable.
Either way, if you only want to update those rows in mainTable that you've just inserted into mainTable the simplest thing to do would be to remember what you've just inserted and update that. A BULK COLLECT seems apposite.
declare
cursor c_all is
select rowid as rid, id, num, status
from maintable
where status = 'FREE'
and rownum <= 100000;
type t__all is table of c_all%rowtype index by binary_integer;
t_all t__all;
begin
open c_all;
loop
fetch c_all bulk collect into t_all limit 10000;
forall i in t_all.first .. t_all.last
insert into datatable (id, num, status)
values (t_all(i).id, t_all(i).num, t_all(i.status));
forall i in t_all.first .. t_all.last
update maintable
set status = 'RESERVED'
where rowid t_all(i).rid;
end loop;
commit;
close c_all;
end;
/
This is not equivalent to your query, it assumes that maintable is unique on NUM. If it unique on ID I would change the UPDATE to a MERGE (it's cleaner) and remove the ROWID column from the cursor:
forall i in t_all.first .. t_all.last
merge into maintable m
using ( select t_all(i).num from dual ) d
on ( m.num = d.num )
when matched then
update
set m.status = 'RESERVED'
As I've written though, if the problem is the selectivity of the columns/indexing you need to post the explain plan, indexes etc.
I think that it is better that you use EXISTS exchange of using in in your update query, it is so faster:
update mainTable m
set m.status = 'RESERVED'
where exists (select * from dataTable where m.num = d.num and d.status = 'FREE');
I am getting the error : unable to get a stable set of rows in the source tables when I ran the below statement.
merge into table_1 c
using (select rep_nbr, T_nbr, SF from table_2) b
on (c.rep_id=b.rep_nbr)
when matched then
update set
c.T_ID =b.T_nbr,
c.SF=b.SF
when not matched then
insert(T_id, SF)
values(null, null);
When i put distinct before the rep_nbr
merge into table_1 c
using (select distinct rep_nbr,t_nbr,SF from table_2) b
on (c.rep_id=b.rep_nbr)
when matched then
update set
c.T_ID =b.T_nbr,
c.SF=b.SF
when not matched then
insert(T_id, SF)
values(null, null);
ORA-01400: cannot insert NULL into c.rep_id.
I don't want to populate c.rep_id, i just need them to match and then update those records that matched.
If I understood correctly, you don't need MERGE, just an UPDATE. Something like this should work:
UPDATE table_1 t1
SET t1.t_id = (SELECT DISTINCT t2.t_nbr FROM table_2 t2 WHERE t1.rep_id = t2.rep_nbr),
t1.sf = (SELECT DISTINCT t2.sf FROM table_2 t2 WHERE t1.rep_id = t2.rep_nbr),
WHERE t1.rep_id IN (SELECT rep_nbr FROM table_2)
But, however, in later versions of Oracle (from 10th or 11th) you can take out parts of merge, for example, take out WHEN NOT MATCHED part.
remove part "with not matched then"
merge into table_1 c
using (select distinct rep_nbr,t_nbr,SF from table_2) b
on (c.rep_id=b.rep_nbr)
when matched then
update set
c.T_ID =b.T_nbr,
c.SF=b.SF
I am trying to do an update and i'm having problems (using microsoft sql server)
update mytable
set myvalue=
(
(select myvalue from someothertable
where someothertable.id=mytable.id)
)
from table mytable
where mytable.custname='test'
Basically the subquery could return no results if that does happen i want to call a different subquery:
(select myvalue from oldtable
where oldtable.id=mytable.id)
well, you could run the second query first, and then, the first query.
In that way, you will override the values only when the first query can bring them, and when the (original) first query won't bring any result, they will have the result of first query.
Also, I think you have a typo in your second query with the table name.
update mytable
set myvalue=
(
select myvalue from oldtable
where oldtable.id=mytable.id
)
from table mytable
where mytable.custname='test'
and exists (select 1 from oldtable
where oldtable.id=mytable.id)
update mytable
set myvalue=
(
select myvalue from someothertable
where someothertable.id=mytable.id
)
from table mytable
where mytable.custname='test'
and exists ( select 1 from someothertable
where someothertable.id=mytable.id)
edit: you will need to add the exists clause, cause if not it will update with null values, I think
You can simply join both tables,
UPDATE a
SET a.myValue = b.myValue
FROM myTable a
INNER JOIN someOtherTable b
ON a.ID = b.ID
WHERE a.CustName = 'test'
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;