Using A SQL JOIN In A SQL DELETE Statement (Thanks Pinal Dave!)

Posted September 4, 2007 at 2:43 PM by Ben Nadel

Tags: SQL

Earlier today, I posted about how John Eric dropped a bomb shell on me, demonstrating that you could run a SQL JOIN statement inside of a SQL UPDATE statement. Well, after reading my blog post, Pinal Dave of The SQL Authority followed up with another revelation - you can do the same thing inside of a SQL DELETE statement. The syntax for this is a bit strange, but perhaps equally powerful.

Taking my previous example with the @boy, @girl, and @relationship tables, I am now updating it such that we are going to delete all boys who have not had the skills to date Winona Ryder. Now, I am not saying that I would necessarily perform the SQL DELETE using this exact methodology, but certainly, it is fun to explore this SQL flexibility.

  • <cfquery name="qUpdateTest" datasource="#REQUEST.DSN.Source#">
  • <!--- Declare in-memory data tables. --->
  • DECLARE
  • @boy TABLE
  • (
  • id INT,
  • name VARCHAR( 30 ),
  • is_stud TINYINT
  • )
  • ;
  •  
  • DECLARE
  • @girl TABLE
  • (
  • id INT,
  • name VARCHAR( 30 )
  • )
  • ;
  •  
  • DECLARE
  • @relationship TABLE
  • (
  • boy_id INT,
  • girl_id INT,
  • date_started DATETIME,
  • date_ended DATETIME
  • )
  • ;
  •  
  •  
  • <!---
  • Populate the boy table with some information.
  • Notice that as I populate the IS_STUD column, all
  • the values are going to be ZERO (meaning that these
  • dudes are not very studly). This will be updated
  • based on the relationship JOIN.
  • --->
  • INSERT INTO @boy
  • (
  • id,
  • name,
  • is_stud
  • )(
  • SELECT 1, 'Ben', 0 UNION ALL
  • SELECT 2, 'Arnold', 0 UNION ALL
  • SELECT 3, 'Vincent', 0
  • );
  •  
  •  
  • <!--- Populate the girl table with some information. --->
  • INSERT INTO @girl
  • (
  • id,
  • name
  • )(
  • SELECT 1, 'Maria Bello' UNION ALL
  • SELECT 2, 'Christina Cox' UNION ALL
  • SELECT 3, 'Winona Ryder'
  • );
  •  
  •  
  • <!--- Populate the relationship table. --->
  • INSERT INTO @relationship
  • (
  • boy_id,
  • girl_id,
  • date_started,
  • date_ended
  • )(
  • SELECT 1, 1, '2007/01/01', NULL UNION ALL
  • SELECT 1, 3, '2004/09/15', '2005/06/15' UNION ALL
  • SELECT 2, 1, '2006/05/14', '2006/05/23'
  • );
  •  
  •  
  • <!---
  • DELETE from the in-memory table. Here, we are going to
  • join the boy, girl, and relationship table to see if
  • any of the boys have NOT been studly enough to date
  • Winona Ryder. We are only interested in keeping boys
  • who have been in this sort of elite relationship.
  •  
  • NOTE: Maria Bello would quite clearly be a studlier
  • conquest, but I am trying to keep in line with my
  • previous UPDATE demo.
  • --->
  • DELETE
  • b
  • FROM
  • @boy b
  • LEFT OUTER JOIN
  • (
  • @relationship r
  • INNER JOIN
  • @girl g
  • ON
  • (
  • r.girl_id = g.id
  • AND
  • g.name = 'Winona Ryder'
  • )
  • )
  • ON
  • b.id = r.boy_id
  • WHERE
  • g.id IS NULL
  • ;
  •  
  •  
  • <!---
  • To see if the delete has taken place, let's grab
  • the records from the boy table; we should now ONLY
  • have boys who have dated Winona Ryder.
  • --->
  • SELECT
  • id,
  • name,
  • is_stud
  • FROM
  • @boy
  • ;
  • </cfquery>
  •  
  •  
  • <!--- Dump out the updated record set. --->
  • <cfdump
  • var="#qUpdateTest#"
  • label="Delete-Updated BOY Table"
  • />

This code has a few cool things in it (in my opinion). For starters, we are demonstrating the whole point of this blog post - running the JOIN inside of the DELETE statement. Here we are using both an INNER JOIN and a LEFT OUTER JOIN. But, we are also performing a LEFT OUTER JOIN to the result of an INNER JOIN of two different tables; that in and of itself is a pretty nifty SQL ability. But anyway, take a look at the final syntax there - we are deleting a table from a table; a little strange, but I guess this is one of those things that you just need to get comfortable with.

Anyway, running the above code, we get the following CFDump output:


 
 
 

 
Using SQL JOIN Inside Of A SQL DELETE Statement  
 
 
 

Notice that now the only record left in the @boy table is Ben - the only one who had a relationship with Winona Ryder. Pretty nifty stuff.

Thanks Pinal Dave!




Reader Comments

Sep 4, 2007 at 3:22 PM // reply »
11 Comments

Ben,

Thanks for posting this article. I glad that you find it useful.
I think my blog reader will find this details very useful as I never wrote about this on my own blog.

Tomorrow I will write down summary and point to this two wonderful (and well explained) post you have. I like your examples.

Regards,
Pinal


Sep 4, 2007 at 3:29 PM // reply »
11,241 Comments

My pleasure. Thanks for the tips.


Sep 7, 2007 at 5:07 PM // reply »
1 Comments

I usually like to use a subquery for delete's as they are simpler and have less room for error. An example would be:

DELETE FROM table
WHERE id IN (SELECT id FROM anothertable WHERE this = 'that')


Sep 7, 2007 at 5:34 PM // reply »
11,241 Comments

@Kevin,

That's definitely the way that I roll most of the time. However (and I don't know if this applies to DELETE statements), when I have used sub-queries with UPDATE statements, I could never alias the table name (syntax error). Using this FROM methodology would allow me to do so and would actually give me more power in my updates.

But, true, more power comes with more complexity. Use the best tool for the situation.


Nov 14, 2008 at 8:34 AM // reply »
1 Comments

Thanks for the tip! Exactly what I needed for my instead of delete trigger!


Apr 2, 2009 at 7:39 AM // reply »
2 Comments

A strange sample ...

Since there aren't foreign key constraints the bug in the sample wasn't seen by nobody ... ;-)

"Arnold" (2) and "Vincent" (3) where deleted but in the relation table still contains an entry with boy_id = 2 ...

I was looking for another but similar sample. I need to purge old date from a huge database.

I need to delete old contracts and all related rows in other tables

e.g.
Contract
- FromParticipant
- ToParticipant
- ContractItem
- TransportPlan
- etc.

Not all contracts having a TransportPlan and not always the From/ToParticipant should be deleted (only if they aren't used somewhere else) etc.


May 25, 2009 at 4:09 AM // reply »
3 Comments

Hi,if a cell contain aa;bb;cc, how am i going to write a statement to delete aa only?
Thanks!


May 25, 2009 at 8:43 AM // reply »
2 Comments

@BabyMilo: In that case you'll use an UPDATE command ... (of course you have to "calculate" the new values before using string functions)


May 25, 2009 at 8:54 AM // reply »
11,241 Comments

@BabyMilo,

Yeah, you have to do an update:

UPDATE [table]
SET [column] = 'bb;cc'
WHERE [column] = 'aa;bb;cc'


May 27, 2009 at 2:13 AM // reply »
3 Comments

What if i want to delete aa only without update all the records? there are plenty of records that contains aa.


May 27, 2009 at 2:13 AM // reply »
3 Comments

What if i want to delete aa only without update all the records? there are plenty of records that contains aa.


May 27, 2009 at 8:26 AM // reply »
11,241 Comments

@BabyMilo,

It won't update all records that contain "aa"; it will only update records that have exactly "aa;bb;cc". That is what the WHERE clause is for.


Jun 23, 2009 at 4:46 AM // reply »
1 Comments

@BabyMilo,
U can write as:

update SomeTable
set SomeColumn = 'xxyyzz' where SomeColumn like '%abc%'


Sep 25, 2009 at 2:48 AM // reply »
1 Comments

This is really a very helpful article.

I always used "In" for deleting a record coz i was not getting any way to Delete records using Select Query just as "Update Select"...

but this article helped me make "Delete Select" kind of query & increased the Query Execution speed

Thanx


Nov 18, 2009 at 7:01 AM // reply »
1 Comments

Thank you! This was very helpful.

I needed to delete from a joining table with a two-field primary key so I couldn't use my normal method since there was no single unique field:
DELETE FROM table WHERE field IN (SELECT...)

Instead I used:

DELETE J

FROM Users U
inner join LinkingTable J on U.id = J.U_id
inner join Groups G on J.G_id = G.id

WHERE G.Name = 'Whatever'
and U.Name not in ('Exclude list')


Jan 17, 2010 at 3:32 PM // reply »
11,241 Comments

@Varsha, @Rob,

Yeah, the IN() approach is good; but using JOINs really gives you some awesome control. Using JOINs in an UPDATE statement is all a lot of fun.


Mar 18, 2010 at 8:45 AM // reply »
1 Comments

Hi guys,

Sort of in response to Kevin..

Just thought I'd point out something to any relative newbies like me trying to use the where clause subquery method with more than one join.

I'm using MS Access for my particular problem. Haven't tried it in grown up T-SQL but trying to make the link in one go with a concatenation made the wonderful Access hang:

WHERE (A & B & C) not in (SELECT (A & B & C)FROM TheOtherTable)

(Obviously for "&" read "+" in T-SQL)

I'm not totally certain this would have any similar trouble in Transact-SQL but for those using Access get rid of the second table from your design view then in SQL you'll need separate subqueries for each join like this:

WHERE
A not in (SELECT A FROM TheOtherTable)
and B not in (SELECT B FROM TheOtherTable)
and C not in (SELECT C FROM TheOtherTable)

There's probably a better way but it's the best I've found so far.

@Kevin,


Mar 18, 2010 at 9:16 AM // reply »
1 Comments

Forget the last part of that.

Wasn't thinking straight and hadn't done it exactly that way myself.

It'll work if you're doing an 'In' but if you're doing a 'Not In' as above it'll do each check across all records separately.

This will be obvious to pros so again I'm only writing for newbies like me.

e.g if you're looking to delete where there's no longer a dog called

A B C
Bingo Barking Chaplin

you won't if there's a another who's first name is Bingo or surname of Chaplin,etc...

(I realise this is an unlikely dataset)

All the best

Some Guy called Adam


Mar 19, 2010 at 8:41 AM // reply »
11,241 Comments

@Some,

I haven't used Access in a while; but, it certainly wouldn't surprise me that it can't handle some of the more processing-intensive query techniques.


Jul 22, 2010 at 10:31 AM // reply »
1 Comments

@Kevin,

Thanks for your query, It was very useful for my case.

Regards,
Sruthi


Apr 6, 2011 at 7:22 AM // reply »
1 Comments

I have to learn how delete a field data from a table. I saw many examples about deleting a row or plural rows. I seek a good example about that..

I thought that.. but it lacks
--
delete from spUrtUretimHareketiDet ...... where nIslemID = 14296683


Apr 17, 2011 at 10:04 PM // reply »
1 Comments

Great post. I tried a: DELETE FROM tablex WHERE id NOT IN (SELECT id FROM tabley LEFT OUTER JOIN...)

Good thing: It works

Bad thing : It is SLLLOWWW when your table has a lot of records. I might try an Index or something else..


Jan 21, 2013 at 5:38 AM // reply »
2 Comments

Please ignore my earliar comments on this as MY Colleague kidding with me.

Sorry once again

Jayant Dass


Jan 30, 2013 at 10:49 AM // reply »
2 Comments

I am so impressed that you can use a JOIN in a delete.

Thanks Ben and Pinal!

SQL GETS HUGE IN A HURRY!



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 4:43 AM
How Do You Use The ColdFusion CFParam Tag?
'<cfparam>' or 'isDefined()and <cfset>' performs the same task.Is there any difference? ... read »
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools