Using CASE Statements In A SQL UPDATE Query

Posted August 30, 2007 at 7:35 AM

Tags: SQL

Nothing revolutionary here, I just recently tried to use a SQL CASE statement as part of an SQL UPDATE statement. I had never tried this before and I am quite happy that it works. I am working on a transactional system that allows for the voiding of account credits. As part of the Void process, I need to make sure that I never let an account balance drop below zero dollars (business requirement - these aren't "real" dollars). In something like ColdFusion, I would use the Max() function:

 Launch code in new window » Download code as text file »

  • Max( 0, (balance - void_credit) )

But, in SQL, the MAX() function performs aggregate calculations on groups, not "max of two numbers" calculations. As such, I tried the following CASE statement:

 Launch code in new window » Download code as text file »

  • <cfquery name="qUpdate" datasource="xxx">
  • UPDATE
  • [account]
  • SET
  • balance =
  • (
  • CASE
  • WHEN
  • ((balance - 10.00) < 0)
  • THEN
  • 0
  • ELSE
  • (balance - 10.00)
  • END
  • )
  • WHERE
  • id = 1
  • </cfquery>

I am hard coding the variables here, but you get the point. I think it's kind of cool that this works. I guess there's nothing about it that should have made me think that it wouldn't work; I just never tried this technique before. I love the fact that you can reference values in the database row that you are going to update. Very cool!

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Reader Comments

Rob Rawlins
Aug 30, 2007 at 8:00 AM // reply »
54 Comments

Nice work Ben,

I always like to see people leaning on thier database a little to do this kind of work for them, many people would simply break that in to two queries, the first being a SELECT and then use CF conditionals to determine the update type.

I'm a big fan of having SQL do this stuff for you, as CF developers its very easy to forget that SQL is an entire language all of its own and is MASSIVLY powerfull for this data manipulation stuff, it took me quite a while to earn full respect for SQL as its own language when I first started developing, but once I did you start thinking about things in a very different way.

Rob


Todd Rafferty
Aug 30, 2007 at 8:25 AM // reply »
165 Comments

MySQL has a Greatest() function:
http://dev.mysql.com/doc/refman/5.1/en/comparison-operators.html#function_greatest

I'm sure the other servers have something equivalent. Otherwise, you'd probably want to use tsql or a stored proc.


Aug 30, 2007 at 9:15 AM // reply »
6,371 Comments

@Rob,

I know what you mean. SQL is awesomely powerful. I am still learning new things all the time. I still have yet to fully understand the whole CONVERT() function and I would love to learn more about Cursors and that sort of stuff.

@Todd,

It looks like MS SQL Server doesn't have the Greatest() equivalent, at least nothing that I could find on Google.


Todd Rafferty
Aug 30, 2007 at 9:23 AM // reply »
165 Comments

@Ben: Yup, tsql it is. Anyway, your case statement works.


JohnEric
Aug 30, 2007 at 9:33 AM // reply »
5 Comments

Another nice technique that I have found invaluable on occasion is using a join in an update statement. I don't know if something like this works on MySQL but on SQL Server you can do something like the following

UPDATE p
SET
p.col1 = p.col1 + q.otherCol
FROM table1 AS p join table2 AS q
ON p.fk_table2_pk = q.pk
WHERE
q.filterColumn = 'something'


Aug 30, 2007 at 9:39 AM // reply »
6,371 Comments

@John,

That is awesome! I knew you could do something like that on a View, but I had no idea you could just update with join usage in a standard statement. Crazy!


Aug 30, 2007 at 10:46 AM // reply »
92 Comments

@Ben/John,

I had just learned you could do joins in an UPDATE SQL statement early last month. I should have guessed you could since the FROM statement is there and joining would making sense if you need to bring data from other locations. I learned how to use it because I needed to move data from one database to another (QA to DEV). It's easy to get lost in SQL but it can really do some neat stuff.


Josh Nathanson
Aug 30, 2007 at 3:08 PM // reply »
17 Comments

It's amazing what SQL can do once you start digging into it.

A little gotcha about CASE statements is that you can only return simple values in your THEN clauses. It's a little less flexible than using dynamic CF in your queries, but as long as you are only looking to return simple values the CASE statement is very powerful.

Also check out IF and IFNULL. IFNULL is nice if for example, your column value is null but you want to return 0:

IFNULL(mycol,0) as col

This will return the column value if it is not null, or 0 if it is null. This can save a lot of extra CF coding if you happen to be in that situation.


Josh Nathanson
Aug 30, 2007 at 3:11 PM // reply »
17 Comments

When I say simple values I mean you can't do something like this:

CASE WHEN 1
THEN 'Where colval = 1'
ELSE
'Where colval = 2'
END

In other words you can't change the structure of the query the way you can using dynamic CF.


Aug 30, 2007 at 7:26 PM // reply »
11 Comments

SQL can do many magical stuff.
I use SQL for all the business logic. I use ColdFusion for presentation.

CASE statement can be effectively used in ORDER BY :
http://blog.sqlauthority.com/2007/07/17/sql-server-case-statement-in-order-by-clause-order-by-using-variable/

People do create whole another SP (as another comment earlier) instead of using CASE.

I use other technologies with SQL but ColdFusion has been my favorite since day one.

Regards,
Pinal


Sep 4, 2007 at 10:38 AM // reply »
6,371 Comments

@John Eric,

I just tried your technique (UPDATE + JOIN) and it works like a charm! Very cool stuff:

http://www.bennadel.com/index.cfm?dax=blog:938.view

Thanks for the hot tip.


Kenny
Oct 23, 2008 at 11:54 AM // reply »
2 Comments

Hi,

What if I want to "switch" the field name? Your example is
Update xxx
Set balance = (Case
.....
End)
Where ......

But I want to do like this:
Update xxx
Set (Case
.....
End) = 1000
Where ......

I have tried this syntax, but it doesn't work. What should I do?
Thanks.


Nov 3, 2008 at 9:39 AM // reply »
6,371 Comments

@Kenny,

Are you trying to dynamically select the actual column to update? Could this be something that would be done more effectively using the parent language (ColdFusion, ASP, etc):

UPDATE xxx
<cfif A>
SET a = 1000
<cfelse>
SET b = 1000
</cfif>
WHERE....

Is that what you're trying to do?


Kenny
Nov 3, 2008 at 11:21 AM // reply »
2 Comments

Yes, that's what I am trying to do. I have many stored procedures update the same table but different fields, and I am thinking to merge them into one sproc. By doing so, the front end developer can just call the same sproc and do several update processes by varying the keywords.


Nov 3, 2008 at 1:29 PM // reply »
6,371 Comments

@Kenny,

You can probably build a dynamic SQL statement and then EXEC() it or something. I've never done this personally, but I think this is how a lot of people handle pagination.


Gonzalo
Mar 25, 2009 at 4:33 PM // reply »
2 Comments

I have the following SQL statement that meets all the requirements of what I am trying to do…

SELECT Diff_Adj,
Case
When Diff_Adj < 0
Then '-'+right ('00000000'+convert (varchar(10), convert (int, -Diff_Adj*100)), 9)
Else right ('000000000'+convert (varchar(10), convert (int, Diff_Adj*100)), 10)
End
FROM dbo.Tran405_CC1

…and these are the results:

Diff_Adj
0000000100
0000000000
0000000000
-000000100
-008638200

Now, instead of running a SELECT statement, I need to run an UPDATE statement to modify data in my table, here is the Update statement I am using to do so…

UPDATE dbo.Tran405_CC1
SET Diff_Adj =
CASE
WHEN Diff_Adj < 0
THEN '-'+right ('00000000'+convert (varchar(10), convert (int, -Diff_Adj*100)), 9)
ELSE right ('000000000'+convert (varchar(10), convert (int, Diff_Adj*100)), 10)
END

…and these are my results:

Diff_Adj
1.00
.00
.00
-1.00
-86382.00

FYI…the data type for Diff_Adj column is Decimal (10, 2)

Thanks in advance


Gonzalo
Mar 25, 2009 at 4:35 PM // reply »
2 Comments

CORRECTED CODE

I have the following SQL statement that meets all the requirements of what I am trying to do…

SELECT Diff_Adj,
Case
When Diff_Adj < 0
Then '-'+right ('00000000'+convert (varchar(10), convert (int, -Diff_Adj*100)), 9)
Else right ('000000000'+convert (varchar(10), convert (int, Diff_Adj*100)), 10)
End
FROM dbo.Tran405_CC1

…and these are the results:

Diff_Adj
0000000001
0000000000
0000000000
-000000001
-000086382

Now, instead of running a SELECT statement, I need to run an UPDATE statement to modify data in my table, here is the Update statement I am using to do so…

UPDATE dbo.Tran405_CC1
SET Diff_Adj =
CASE
WHEN Diff_Adj < 0
THEN '-'+right ('00000000'+convert (varchar(10), convert (int, -Diff_Adj*100)), 9)
ELSE right ('000000000'+convert (varchar(10), convert (int, Diff_Adj*100)), 10)
END

…and these are my results:

Diff_Adj
1.00
.00
.00
-1.00
-86382.00

FYI…the data type for Diff_Adj column is Decimal (10, 2)

Thanks in advance


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 7, 2009 at 5:53 PM
Ask Ben: Javascript String Replace Method
You can find here an advanced function that prepared with javascript replace function. This can make the first letters of words, sentences, lines and whatever you define automatically: http://www.m ... read »
Andrew Neely
Nov 7, 2009 at 4:56 PM
A Moment That Touched Me - The Fountainhead
Ben, Glad you enjoyed the podcast. Yeah, the Tank Riot guys can get really chatty during the episodes, but that's part of the charm of it for me. They've covered everything from Nichola Tesla to Cha ... read »
Nov 7, 2009 at 4:43 PM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
Is it possible to make some more Menü`s ? ... read »
Jill
Nov 7, 2009 at 11:40 AM
How To Unformat Your Code (Like A Pro)
Derek, I think you might be right - sweet! Thanks for the link :) ... read »
Nov 7, 2009 at 11:25 AM
How To Unformat Your Code (Like A Pro)
I think it would be way easier to just use this http://www.logichammer.com/html-formatter/ He just released v3 and it rocks. ... read »
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »