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;
Related
I have 2 tables that I need to update:
Table A consists of: ID, personName, Date, status
Table B consist of: PersonID, Date, status
For every row in A there can be multiple rows in B with the same personID
I need to "loop" over all results from A that the status=2 and update the date and status to 1.
Also, for every row in A that status=2 I need to update all the rows in B that has the same personID (i.e, A.ID==B.PersonID) – I need to update date and status to 1 as well.
So basically, if I was to do this programmatically (or algorithmically) its's something like that:
Foreach(var itemA in A)
If (itemA.status = 2)
itemA.status to 1
itemA.date = GetDate()
foreach(var itemB in B)
if(itemB.PersonID == itemA.ID && itemB.status != 2 )
Change itemB.status to 1
Change itemB.date = GetDate()
i know how to update all the rows in B using the following sql statement:
UPDATE
B
SET
status = 1,
date = GETDATE()
FROM
B
INNER JOIN
A
ON
B.PersonID = A.ID
the problem is that i don't know how to also update table A since there can't be multiple tables in an update statement
thanks for any help
Here is an example using the output clause:
declare #ids table (id int);
update table1
set status = 1
output inserted.id into #ids
where status = 2;
update table2
set status = 1,
date = getdate()
where personid in (select id from #ids);
Put everything inside a transaction and commit if succeeds
DECLARE #err int
BEGIN TRANSACTION
UPDATE B
SET status = 1, date = GETDATE()
FROM B INNER JOIN A ON B.PersonID = A.ID
WHERE A.status = 2
SET #err = ##ERROR
IF #err = 0
BEGIN
UPDATE A
SET status = 1,
date = GETDATE()
WHERE status = 2
SET #err = ##ERROR
END
IF #err = 0
COMMIT
ELSE ROLLBACK
Question has been asked before:
How to update two tables in one statement in SQL Server 2005?
it is not possible to update multiple tables at once.
Summary answer from that question:
You can't update multiple tables in one statement, however, you can use a transaction to make sure that two UPDATE statements are treated atomically. You can also batch them to avoid a round trip.
BEGIN TRANSACTION;
UPDATE Table1
SET Table1.LastName = 'DR. XXXXXX'
FROM Table1 T1, Table2 T2
WHERE T1.id = T2.id
and T1.id = '011008';
UPDATE Table2
SET Table2.WAprrs = 'start,stop'
FROM Table1 T1, Table2 T2
WHERE T1.id = T2.id
and T1.id = '011008';
COMMIT;
For your question something like this would work:
BEGIN TRANSACTION;
UPDATE B
SET status = 1
, date = GETDATE()
WHERE B.PersonId IN ( SELECT ID
FROM A
WHERE A.status = 2
);
UPDATE A
SET status = 1
, date = GETDATE()
WHERE A.status = 2;
COMMIT;
select * from tbl_a;
SRNO T_TEXT
1 a
1 b
1 c
2 a
2 b
3 a
3 b
4 a
----
select * from tbl_b;
SRNO T_TEXT
1
1
1
2
2
3
3
4
i want to update tbl_b.t_text with values from tbl_a.t_text.
i do that it gives returned too many rows. I can do this trough a for loop,
but want it through update statement only.
Here is the SQL I've tried#
update tbl_b b
set b.t_text = (select a.t_text from tbl_a a
where a.srno = b.srno and b.t_text is null)
where exists ( select 1 from tbl_a c
where c.srno = b.srno);
It throws error single row subquery return more than one row.
You can use this code to update tbl_b
begin
for i in (select a.* from tbl_a a) loop
update tbl_b b
set b.t_text=i.t_text
where b.srno=i.srno
and b.t_text is null
and rownum=1;
end loop;
end;
I wish it helps you.
you can use Below query
UPDATE tbl_a
SET tbl_a.T_TEXT=(SELECT tbl_b.T_TEXT
FROM tbl_b
WHERE tbl_b.SRNO=tbl_a.SRNO);
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;
I have found lots of posts on coniditonal filtering in the where clause, but they all seem to be based off of using the same value, such as:
WHERE (o.OrderID = #orderid OR #orderid IS NULL)
I need to do something slightly different, I need to remove a filter and its value completely base on another value, so something like:
select *
from tableA
where 1 = 1
case when a = 1 then
and b in (select b from tableB)
else
-- do nothing
end
I know that the above is not allowed, and I am just writing as an example of what I am trying to do. does Anyone have any idea of a good way to do this? I know i could use if statements and duplicate the query, but it is a large one, and i am trying to avoid that.
Thanks
SELECT *
FROM tableA
WHERE a <> 1
OR (a = 1 AND EXISTS(SELECT b from TableB WHERE tableA.b = TableB.b))
You could also write this as:
SELECT tableA.*
FROM tableA
LEFT JOIN tableB
ON tableA.b = tableB.b
WHERE tableA.a <> 1
OR (tableA.a = 1 AND tableB.b IS NOT NULL)
"Correcting" your WHERE clause:
select *
from tableA
where 'T' = case
when a = 1 then case
when b in (select b from tableB) then 'T'
end
else 'T'
end;
I have a tableA:
ID value
1 100
2 101
2 444
3 501
Also TableB
ID Code
1
2
Now I want to populate col = code of table B if there exists ID = 2 in tableA. for multiple values , get max value.
else populate it with '123'. Now here is what I used:
if exists (select MAX(value) from #A where id = 2)
BEGIN
update #B
set code = (select MAX(value) from #A where id = 2)
from #A
END
ELSE
update #B
set code = 123
from #B
I am sure there is some problem in BEGIN;END or in IF EXIST;ELSE.
Basically I want to by-pass the else part if select statement in IF-part exist and vice- versa. For example if select statement of IF=part is:
(select MAX(value) from #A where id = 4)
It should just populate 123, coz ID = 4 do not exist !
EDIT
I want to add the reason that your IF statement seems to not work. When you do an EXISTS on an aggregate, it's always going to be true. It returns a value even if the ID doesn't exist. Sure, it's NULL, but its returning it. Instead, do this:
if exists(select 1 from table where id = 4)
and you'll get to the ELSE portion of your IF statement.
Now, here's a better, set-based solution:
update b
set code = isnull(a.value, 123)
from #b b
left join (select id, max(value) from #a group by id) a
on b.id = a.id
where
b.id = yourid
This has the benefit of being able to run on the entire table rather than individual ids.
Try this:
Update TableB Set
Code = Coalesce(
(Select Max(Value)
From TableA
Where Id = b.Id), 123)
From TableB b
I know its been a while since the original post but I like using CTE's and this worked for me:
WITH cte_table_a
AS
(
SELECT [id] [id]
, MAX([value]) [value]
FROM table_a
GROUP BY [id]
)
UPDATE table_b
SET table_b.code = CASE WHEN cte_table_a.[value] IS NOT NULL THEN cte_table_a.[value] ELSE 124 END
FROM table_b
LEFT OUTER JOIN cte_table_a
ON table_b.id = cte_table_a.id