This post is about a handy little function that works across many database systems, including Sql Server, Oracle, and MySql. I often forget about it and at times even end up coding some workaround that would have been a lot easier if I had just used NullIf(). NullIf takes two parameters. The first parameter is the value to check and the second parameter is the value that should equate to NULL. Let’s take a look at an example to hopefully make this clearer.
First, we will create a table to work from, populate it with some data, and select the results out so that we can see what we have visually.
USE tempdb GO CREATE TABLE dbo.JunkData ( JunkDataId INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, Name VARCHAR(100) NOT NULL, StreetAddress VARCHAR(100) NULL ); INSERT dbo.JunkData (Name, StreetAddress) SELECT 'Pete', '777 Main St'; INSERT dbo.JunkData (Name, StreetAddress) SELECT 'Jeff', NULL; INSERT dbo.JunkData (Name, StreetAddress) SELECT 'Dustin', '999 Oak St'; INSERT dbo.JunkData (Name, StreetAddress) SELECT 'Ron', NULL; INSERT dbo.JunkData (Name, StreetAddress) SELECT 'Keith', ''; SELECT Name, StreetAddress FROM dbo.JunkData;
In this case, the Street Address column is nullable, but for Keith’s record the developer chose to insert a blank space instead of a NULL for a missing address. If we try to just write a query to get rid of the nulls, we still have the blank space issue. Here is a query that uses COALESCE to get rid of the NULLS and its results.
SELECT Name, COALESCE(StreetAddress, 'Not Provided') AS StreetAddress FROM dbo.JunkData;
You see that we still have the blank address to deal with. One work around is to use a case statement. Something like “CASE WHEN COALESCE(StreetAddress, ‘Not Provided’) = ” THEN ‘Not Provided’ ELSE COALESCE(StreetAddress, ‘Not Provided’) END AS StreetAddress”. But, that is quite a mouthful and we repeat ourselves several times. However, if we could get COALESCE to treat a blank address like a NULL, we’d have been in business in the first place. That is what NULLIF() does. It evaluates the value we specify as a NULL (in this case a blank space) and then the rest of the query can treat it like a NULL. Here is that example
SELECT Name, COALESCE(NULLIF(StreetAddress, ''), 'Not Provided') AS StreetAddress FROM dbo.JunkData;
That’s much more succinct and I feel like it conveys our intent much more easily. Here’s another practical use case for NULLIF(). Given the following table and values, we want to find the average sale on each given day.
CREATE TABLE dbo.Reporting( RowId INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, SalesDate DATETIME NOT NULL, TotalSales MONEY NOT NULL, QuantitySold NUMERIC(9,2) NOT NULL ); INSERT dbo.Reporting(SalesDate, TotalSales, QuantitySold) SELECT '4/1/16', 432.50, 2; INSERT dbo.Reporting(SalesDate, TotalSales, QuantitySold) SELECT '4/2/16', 0.00, 0; INSERT dbo.Reporting(SalesDate, TotalSales, QuantitySold) SELECT '4/3/16', 5422.10, 10;
We might write something like the following
SELECT SalesDate, (TotalSales/QuantitySold) as AverageSale FROM dbo.Reporting;
However, when you do, you get a divide-by-zero error. Sometimes in more complicated situations, that can be a bear to track down exactly what is evaluating to zero in an equation. However, if you ask the denominator to evaluate as NULL whenever it is 0, SQL is much happier. Here’s our query now:
SELECT SalesDate, (TotalSales/NULLIF(QuantitySold, 0)) as AverageSale FROM dbo.Reporting;
Now, we easily get our results.
This helps identify which records are causing our issue and can now easily be dealt with. If we don’t like NULL in our results, we can use ISNULL() or COALESCE() to put a sensible default answer. Done and done.