SQL Case Statement

November 5, 2012

In SQL, the CASE statement can be used to further control the output of a column, or limit the choices that are returned.

Due to the particular case I'm dealing with, this query will return a list of band names and their regions. Regions are the ISO country code (no=Norway, nz=New Zealand, ch=Switzerland) except where it is in the uk, when four different regions are listed: england, wales, scotland, northernireland.

SELECT b.name, r.country_code 
FROM bands_band b
INNER JOIN regions_region r ON r.id = b.region_id

This outputs data in the following format:

                                   name                                    |  country_code   
---------------------------------------------------------------------------+-----------------
 Dublin Concert                                                            | ie
 Dundalk Concert Brass Band                                                | ie
 Brass Band Rotterdam                                                      | nl
 Connacht Brass                                                            | ie
 Ceramic City Brass                                                        | england
 1st Renfrew R.V. (Greenock) Brass Band                                    | scotland
 Bedliniog                                                                 | wales
 St Cynons                                                                 | wales
 New Cross SE Railway Mission                                              | england

Lets say we want to output the real ISO country code (gb) for the uk regions in a new column, otherwise we want it to contain the existing code. We can do this with a case statement.

SELECT 
  b.name, 
  r.country_code, 
  CASE r.country_code
     WHEN 'england' THEN 'gb'
     WHEN 'wales' THEN 'gb'
     WHEN 'scotland' THEN 'gb'
     WHEN 'northernireland' THEN 'gb'
     ELSE r.country_code
  END as iso_code
FROM bands_band b
INNER JOIN regions_region r on r.id = b.region_id

The results of this query are:

                                   name                                    |  country_code   | iso_code 
---------------------------------------------------------------------------+-----------------+----------
 Dublin Concert                                                            | ie              | ie
 Dundalk Concert Brass Band                                                | ie              | ie
 Brass Band Rotterdam                                                      | nl              | nl
 Connacht Brass                                                            | ie              | ie
 Ceramic City Brass                                                        | england         | gb
 1st Renfrew R.V. (Greenock) Brass Band                                    | scotland        | gb
 Bedliniog                                                                 | wales           | gb
 St Cynons                                                                 | wales           | gb
 New Cross SE Railway Mission                                              | england         | gb

Order By

You can also use the case statement as part of an order by clause

SELECT 
  b.name, 
  r.country_code
FROM bands_band b
INNER JOIN regions_region r on r.id = b.region_id
ORDER BY
  CASE r.country_code
     WHEN 'england' THEN 'gb'
     WHEN 'wales' THEN 'gb'
     WHEN 'scotland' THEN 'gb'
     WHEN 'northernireland' THEN 'gb'
     ELSE r.country_code
  END

This will order the results by the country_code column, but place all england, wales, scotland, northernireland matching rows between fr and ie, as it's using gb for ordering.

The order within gb is not set, but adding a second order by column like this will ensure that the rows within gb are also grouped into the four regions:

SELECT 
  b.name, 
  r.country_code
FROM bands_band b
INNER JOIN regions_region r on r.id = b.region_id
ORDER BY
  CASE r.country_code
     WHEN 'england' THEN 'gb'
     WHEN 'wales' THEN 'gb'
     WHEN 'scotland' THEN 'gb'
     WHEN 'northernireland' THEN 'gb'
     ELSE r.country_code
  END, r.country_code

Tags: sql case oracle postgres