How to update multiple tables with single query - sql

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;

Related

Using a trigger to insert values into another table unless value exists in which case update

I have a table (Table1) which has three columns: 'ID' , 'Status' , 'Title'. I have second table (Table2) that has three columns: 'ID' , 'Table1ID' , 'Title'.
ID is a sequential number value, title is an alphanumeric value and status have values of either 0 or 1. Starting with a value of 0 when the record is created in Table1.
What I'm trying to achieve is a trigger: that when [Table1].Status changes from value 0 to 1 then to insert a new row into [Table2] with the value of [Table1].ID into [Table2].Table1ID and [Table1].Title into [Table2].Title of only the updated record in [Table1].
However if [Table2].Table1ID already has a matching value of [Table1].ID on the updated value then instead of inserting a new row it should simply update the value of [Table2].Title.
Here's what I've attempted so far:
Create Trigger [dbo].[test]
ON [dbo].[Table1]
After Update
As Begin
Set NOCOUNT ON;
IF UPDATE (Status)
Begin
INSERT INTO [Table2]
VALUES ((SELECT DISTINCT ID FROM INSERTED WHERE NOT EXISTS (SELECT * FROM TABLE2 WHERE TABLE2.TABLE1ID = INSERTED.ID)))
END
END
Go
If I understand all the requirements I think you need something like this. First it will update Table2 only when the status changes. Since you are updating the Title I would think you would update it when the value of Title changes but that isn't what you stated you want.
Then it will insert any rows that don't exist already.
Please notice that this will work no matter how rows get updated in a single update statement.
Create Trigger [dbo].[test]
ON [dbo].[Table1]
After Update
As Begin
Set NOCOUNT ON;
--first we need to update any existing rows in Table2
update t2
set Title = i.Title
from inserted i
join deleted d on d.ID = i.ID
join Table2 t2 on t2.ID = i.ID
where d.Status = 0 --only where the row in Table1 has a status of 0
and i.Status = 1 --only when the new value has status = 1
--now we can insert any rows that don't already exist into Table2
INSERT INTO [Table2]
(
ID
, Title
)
SELECT i.ID
, i.Title
FROM INSERTED i
WHERE NOT EXISTS
(
SELECT *
FROM TABLE2
WHERE TABLE2.TABLE1ID = i.ID
)
END

Update table from another table SQL

Ive hit a wall with what seems a simple procedure.
Update a table from another table, heres where i am:
DECLARE #oldcode varchar(50)
DECLARE #newcode varchar(50)
SET #oldcode = table1.OLDCODE
SET #newcode = table1.NEWCODE
UPDATE table2 SET [CODE] = #NEWCODE WHERE [CODE] = #OLDCODE
this results in:
The multi-part identifier "table1.OLDCODE" could not be bound.
cheers :-
the data:
Table1
record OLDCODE NEWCODE
1 ZZZALF38 ALF38
2 ZZZALF38.1 ALF38.1
3 ZZZALF38.2 ALF38.2
table2
record CODE
1 ZZZALF38
2 ZZZALF38.1
3 ZZZALF38.2
wish to change table 2 to:
record CODE
1 ALF38
2 ALF38.1
3 ALF38.2
I am guessing you are using SQL Server and this is what you want:
update t2
set code = t1.newcode
from table2 t2 join
table1 t1
on t2.code = t1.oldcode;
update table2 set code=table1.newcode from table1 on table2.code=table1.code

Why do these sql counts not match up

i would expect these counts to match but they are off by a few records. What could cause this?
DECLARE #ExpectedCount INT = 0;
DECLARE #UpdatedCount INT = 0;
SELECT #ExpectedCount = COUNT(*)
FROM [dbo].[Table1] t
JOIN [dbo].[Table2] s ON s.IdColumn = t.IdColumn
UPDATE t
SET t.StadiumId = s.StadiumId
FROM [dbo].[Table1] t
JOIN [dbo].[Table2] s ON s.IdColumn = t.IdColumn
SELECT #UpdatedCount = ##ROWCOUNT
PRINT #ExpectedCount
PRINT #UpdatedCount
SELECT COUNT(*) will show the number of rows in the JOIN of t1 and t2.
##ROWCOUNT after UPDATE ... t1 JOIN t2 will have the number of rows updated in t1.
The numbers are different because they are counting different things. A trivial explanation is a row in t1 for which there are two rows matching in t2: the COUNT(*) is 2, the UPDATE count is 1. QED.
Instead try this UPDATE
UPDATE [dbo].[Table1]
SET StadiumId = s.StadiumId
FROM [dbo].[Table2] s
WHERE s.IdColumn = [dbo].[Table1].IdColumn

Deleting rows in a table a chunk at a time

I have a single-column table Ids, which whose column ID is of type uniqueidentifier. I have another table MyTable which has an ID column as well as many other columns. I would like to delete rows from MyTable 1000 at a time, where the ID from MyTable matches an ID in Ids.
WHILE 1 = 1 BEGIN
DELETE t FROM (SELECT TOP 1000 ID FROM Ids) d INNER JOIN MyTable t ON d.ID = t.ID;
IF ##ROWCOUNT < 1 BREAK;
WAITFOR DELAY #sleeptime; -- some time to be determined later
END
This doesn't seem to work though. What should the statement actually be?
Try this:
DECLARE #BatchSize INT
SET #BatchSize = 100000
WHILE #BatchSize <> 0
BEGIN
DELETE TOP (#BatchSize) t
FROM [MyTable] t
INNER JOIN [Ids] d ON d.ID=t.ID
WHERE ????
SET #BatchSize = ##rowcount
END
Has the benefit that the only variable you need to create is the size, as it uses it for the WHILE loop check. When the delete gets below 100000, it will set the variable to that number, on the next pass there will be nothing to delete and the rowcount will be 0... and so you exit. Clean, simple, and easy to understand. Never use a CURSOR when WHILE will do the trick!
Try
Delete from MyTable
Where ID in
(select top 1000 t.ID
from Ids t inner
join MyTable d on d.Id = t.Id)
You could also try:
set rowcount 1000
delete from mytable where id in (select id from ids)
set rowcount 0 --reset it when you are done.
http://msdn.microsoft.com/en-us/library/ms188774.aspx
WHILE EXISTS (SELECT TOP 1 * FROM MyTable mt JOIN IDs i ON mt.ID = t.ID)
BEGIN
DELETE TOP (1000) FROM MyTable
FROM MyTable mt JOIN IDS i ON mt.ID = i.ID
--you can wait if you want, but probably not necessary
END
--Sorry for the quick post; was in a hurry :)
The DELETE statement in SQL Server supports two FROM clauses; the first FROM identifies the table that is having rows deleted, and the second FROM clause is used for JOINS.
See: http://msdn.microsoft.com/en-us/library/ms189835.aspx

SQL Server: IF EXISTS ; ELSE

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