Jeg har gennem mange år være flittig bruger af ISNULL funktionen i t-sql. Den anden dag fik jeg en fejl ind fra en kunde, som søgte på en værdi vedkommende viste fandtes i deres system, men søgning kunne ikke finde recorden.
Efter at have kigge i min stored procedure noget tid, uden at finde fejlen, begyndte jeg at teste på et sted hvor jeg brugte ISNULL.
Problemet er bedst illustreret med et eksempel, lad os oprette en tabel til at teste med:
DECLARE @Customers TABLE (
Id INT,
InternalName NVARCHAR(10),
Firstname NVARCHAR(10),
Lastname NVARCHAR(10)
)
INSERT INTO @Customers (
[Id],
[InternalName],
[Firstname],
[Lastname]
) VALUES (
1,
NULL,
N'Dennis',
N'Knappe'
)
Nu har vi en tabel med en NULL værdi i InternalName feltet, og Dennis i FirstName og Knappe i LastName. Lad os så prøve at lave en forespørgsel:
SELECT ISNULL(InternalName, FirstName +' '+ LastName) AS CustomerName
FROM @Customers
Hvad returnere denne forespørgsel? Hvis du ligesom mig trode at den returnerede Dennis Knappe, kan du godt læse videre.
Jeg løfter sløret allerede nu. Den returnerer:
Dennis Kna
Ja, det er rigtigt. Det lader til at ISNULL tager datatypen fra det første argument og caster det sidste argument til samme længde. Altså vil min FirstName + ' ' + LastName blive til NVARCHAR(10). Jeg må indrømme at det tog lidt tid at hitte ud af. Jeg forsøgte efterfølgende at kigge i dokumentationen for ISNULL hos M$, men der står intet om denne lille "feature" og der står, som Jakob rigtig nok skriver i mine kommentarer: replacement_value must have the same type as check_expresssion. Jeg har åbenbart været lidt for hurtig på aftrækkeren, og ikke læst det som stor ordentligt. Anyway er der måske flere af min slags derude, og de får hermed glæde af løsningen :-)
(teksten efter overstregning er tilføjet efter publish af dette blogindlæg)
Løsningen på problemet
Jeg kan umiddelbart se to muligheder for at komme rundt om dette problem, du får dem begge her:
1. Løsning med at caste argument to til den længede man ønsker:
SELECT ISNULL(CAST(InternalName AS NVARCHAR(20)), FirstName +' '+ LastName) AS CustomerName
FROM @Customers
2. Brug COALESCE (mit valg)
SELECT COALESCE(InternalName, FirstName +' '+ LastName) AS CustomerName
FROM @Customers
Coalesce funktionen er åbenbart ligeglad med at typerne ikke er helt ens, hvilket jeg også havde forventet at ISNULL var.
/END TRANSACTION