Batch Delete from tableA based on data on tableB - sql

I'm trying to implement a batch delete.
I found this code on the internet:
DECLARE #rowcount int = 1
WHILE (#rowcount != 0 ) BEGIN
DELETE T1
FROM (SELECT TOP (50) * FROM Orders WHERE OrderCity = #city) T1
SELECT #rowcount = ##ROWCOUNT
END
the idea is to delete all orders from #city
It seems to work fine but on my reality, I need to delete from Orders where OrderCity in (select ID from SomeOtherTable)
If I try to do the same, it works but it takes a lot of time because SomeOtherTable will contain around 1.5 million rows and the data is being deleted from the main table, so it doesnt get any smaller (it does not contains cities, its another thing).
I also cant join both tables because it wont run saying that more than one table will be affected.
So basically my question is: Is there anyway to batch delete from tableA where tableA.ID IN (select ID from tableB)

Yes you can do it without join as:
DELETE tableA
FROM tableB
WHERE tableA.ID = tableB.ID

Delete Order
FROM
Order INNER JOIN SomeOtherTable ON Order.OrderCity = SomeOtherTable.ID
This could solve your problem

You should be able to delete based on a join. Try
DELETE FROM tableA
FROM tableA A
JOIN tableB B ON A.ID = B.ID
Also, if tableB has ~ a million rows, it would really help if you have an index on the ID column.

Related

Join equivalent query

I have a simple enough query that will be used as part of a SP to clean the database from time to time. TableA and TableB are related with a ID. I build a table variable with all the IDs in TableA and then delete all the one that appear in TableB. This sintax works just fine:
DELETE #TableIds
FROM #TableIds AS tids
WHERE tids.sharedID IN (SELECT tb.sharedID FROM TableB AS tb WITH (nolock))
How can this query be done with a JOIN instead of a IN (subquery)?
You don't need a table variable to do this. Use delete with a join so the matched id records can be deleted.
delete a
from tablea a
join tableb b on a.id=b.id
Try like below
DELETE Tids
FROM #TableIds AS tids
INNER JOIN TABLEb TB(Nolock) ON TIDS.SHAREID= TB.SHAREId

SQL update a column to equal a column from a join and using a subquery

I have two tables which handles stock and have been getting out of sync recently.
The data needs to be updated to be in sync again and tableB is always correct so we base the update on this table and use the data from this table to update tableA.
I am attempting to update via a join.
With the below code I have tried multiple different ways to update, for example using a where statement on the xcolumn2, removing the selecting part etc.
Is there a piece of syntax I am missing or am I going the wrong way about it?
update tableA
set tableA.columnA = tableB.columnA
--select
--tableA.xcolumn2,
--tableA.columnA,
--tableB.columnA,
--from tableA as tableA
left join
(select xcolumn1, xcolumn2, sum(columnA) as columnA, sum(xcolumn3) as xcolumn3
from tableB as tableB group by xcolumn1, xcolumn2) as tableB
on tableA.xcolumn2 = tableB.xcolumn2
group by
tableA.xcolumn2,
tableA.columnA,
tableB.columnA,
having sum(tableA.columnA) != sum(tableB.columnA)
I would imagine your update should look something like this:
UPDATE tableA
SET tableA.columnA = tableB.columnA
FROM tableA
JOIN ( SELECT xcolumn1 ,
xcolumn2 ,
SUM(columnA) AS columnA
FROM tableB AS tableB
GROUP BY xcolumn1 ,
xcolumn2
) AS tableB
ON tableA.xcolumn2 = tableB.xcolumn2
AND tableA.xcolumn1 = tableB.xcolumn1
AND (tableA.columnA <> tableB.columnA
OR tableA.columnA IS NULL)

How to loop through rows in two tables and create a new set based on the merged results in SQL

Here is my obstacle.
I have two tables. Table A contains more rows than Table B. I have to merge the results and if Table A does not contain a row from Table B then I insert it into the new set. If however, a row from Table A contains a row with the same primary key as Table B, the new set will take the row from Table B.
Would this best be done in a cursor or is there an easier way to do this? I ask because there are 20 million rows and while I am new to sql, i've heard cursors are expensive.
Your phrasing is a little vague. It seems that you want everything from TableB and then rows from TableA that have no matching primary key in B. The following query solves this problem:
select *
from tableB union all
select *
from tableA
where tableA.pk not in (select pk from tableB)
Yep, cursors are expensive.
There's a MERGE command in later versions of SQL that will do this in one shot, but it's sooo cumbersome. Better to do it in two pieces - first:
UPDATE A SET
field1 = B.field1
,field2 = B.field2
, etc
FROM A JOIN B on B.id = A.id
Then:
INSERT A SELECT * FROM B --enumerate fields if different
WHERE B.id not in (select id FROM A)
An OUTER JOIN should do what you need and be more efficient than a cursor.
Try this query
--first get the rows that match between TableA and TableB
INSERT INTO [new set]
SELECT TableB.* --or columns of your choice
FROM TableA LEFT JOIN TableB ON [matching key criteria]
WHERE TableB.[joining column/PK] IS NOT NULL
--then get the rows from TableA that don't have a match
INSERT INTO [new set]
SELECT TableA.* --you didn't say what was inserted if there was no matching row
FROM TableA LEFT JOIN TableB ON [matching key criteria]
WHERE TableB.[joining column/PK] IS NULL

How do you return data Joined with a Blacklist table?

Please review this statement:
SELECT TableID FROM Table t1
INNER JOIN BlackList b ON b.TableID <> t1.TableID
I was thinking this statement returned everything from Table that wasn't found in the Blacklist table, but instead it returned nothing at all (0 rows). If I'm trying to return everything from Table that IS NOT found in the Blacklist table, what's the best way to do this? I assume you can do this:
SELECT TableID FROM (
SELECT TableID, CASE WHEN b.TableID IS NULL THEN 1 ELSE 0 END OnBlackList
FROM Table t1
LEFT JOIN Blacklist b ON b.TableID = t1.TableID
) tb1
WHERE tb1.OnBlackList = 0
But I was looking for a shorter, more efficient solution. Any suggestions?
SELECT TableID FROM dbo.Table
EXCEPT
SELECT TableID FROM dbo.Blacklist;
One basic way is using a NOT EXISTS:
SELECT TableID FROM Table t1
where NOT EXISTS (select * from BlackList b where b.TableID = t1.TableID);
This will select rows in t1 that are not present in the BlackList table.
SELECT TableT1.TableId FROM TableT1
LEFT OUTER JOIN BlackList ON
TableT1.TableID = BlackList.TableID
where BlackList.TableId IS NULL
I wrote the above, but now I also found a previous question/ answer in StackOverflow:
How to find rows in one table that have no corresponding row in another table
Also:
SELECT TableId FROM Table
WHERE TableId NOT IN (SELECT TableID FROM BlackList)
This will work regardless of the columns you add in the main select statement.

SQL Delete based on condition in join

It is possible to delete records based on a satisfied condition with a join query?
For instance, I have a linking table joining 3 records. The query I have at the moment deletes records from this table where one of the id's isn't IN() an imploded Php array. I've come to realise that the query should only remove records from this table if the id's don't exist in the array and they belong to a certain other table based on the a link to another table.
For SQL Server, the command is slightly different:
DELETE FROM TableA
FROM TableA LEFT OUTER JOIN TableB ON TableA.Column = TableB.Column
WHERE TableB.Column IS NULL
No, that's not a typo, yes, you do need "FROM TableA" twice. At least, you need the second FROM (the first is optional). The following has the advantage that it works for both SQL Server and MySQL:
DELETE TableA
FROM TableA LEFT OUTER JOIN TableB ON TableA.Column = TableB.Column
WHERE TableB.Column IS NULL
I like to use EXISTS clauses for this:
DELETE FROM TableA
WHERE
<<put your array condition here>>
AND NOT EXISTS
(SELECT 1 FROM TableB Where TableB.ID=TableA.ID)
You can use :
DELETE Based on a Join:
DELETE A
FROM TableA AS A
LEFT OUTER JOIN TableB As B ON A.Id = B.TabaleAId
WHERE B.Column IS NULL
Delete With SubQuery:
DELETE
FROM TableA AS A
Where
A.id not in ( Select B.TabaleAId From Tab;eB As B )
or
DELETE FROM TableA
WHERE Not EXISTS
(
SELECT *
FROM TableB As B
Where B.TableAId = TableA.Id
)
DELETE Using Table Expressions:
With A
As
(
Select TableA.*
FROM TableA AS A
LEFT OUTER JOIN TableB As B ON A.Id = B.TabaleAId
WHERE B.Column IS NULL
)
Delete From A
DELETE FROM TableA
LEFT OUTER JOIN TableB
WHERE TableB.Column IS NULL
Will delete the records in tableA that don't have a corresponding record in TableB. Is that like what you are after?
DELETE FROM a
FROM TableA AS a LEFT OUTER JOIN TableB AS b
on a.CALENDAR_DATE = b.CALENDAR_DATE AND a.ID = b.ID
Where b.ID is null
You can first use the select statement and verify your records that you want to delete and then remove the select statement and add Delete FROM tablename with the above query syntax.
The easiest way to Delete based on join is as follow:
1.Write your query using SELECT statement instead of DELETE statement
SELECT COLUMNS
FROM Table1
INNER JOIN Table2 ON Table1.YYY = Table2.XXX
2.Replace SELECT COLUMNS with DELETE FROM TABLE
DELETE FROM Table1
FROM Table1
INNER JOIN Table2 ON Table1.YYY = Table2.XXX
Note that we need to specify FROM twice, one for DELETE part and one for JOIN part.
delete from TableA
where id in
(
select id from TableA
except select id from TableB
)
Which means "delete from tableA where id in table a but not in table b)
Otherwise a Merge statement might help you (when matched/not matched delete etc)
http://technet.microsoft.com/en-us/library/bb510625.aspx