DECLARE @T TABLE
(
ID BIGINT IDENTITY PRIMARY KEY,
FaceBookID BIGINT NULL,
TwitterID BIGINT NULL,
LinkedInID VARCHAR(50) NULL
);
INSERT INTO @T (FaceBookID, TwitterID, LinkedInID)
VALUES (11111111, NULL, NULL)
INSERT INTO @T (FaceBookID, TwitterID, LinkedInID)
VALUES (NULL, 22222222, NULL)
INSERT INTO @T (FaceBookID, TwitterID, LinkedInID)
VALUES (NULL, NULL, '3333333')
DECLARE @UserType VARCHAR(10)
SET @UserType = 'LinkedIn'
DECLARE @oAuthID VARCHAR(50)
SET @oAuthID = 'aaaaaaa'
DECLARE @UserID BIGINT
SELECT @UserID = (
SELECT ID FROM @T
WHERE (@UserType = 'FaceBook' AND [FaceBookID] = CAST(@oAuthID AS BIGINT))
OR (@UserType = 'Twitter' AND [TwitterID] = CAST(@oAuthID AS BIGINT))
OR (@UserType = 'LinkedIn' AND [LinkedInID] = @oAuthID)
)
SELECT @UserID
PROBLEM:
Even when the UserType is ‘LinkedIn’ the first WHERE clause gets executed completely and the SQL tries to CAST the value of @oAuthID, which in this case is ‘aaaaaaa’, into a BIGINT.
QUESTION:
How can I write a WHERE CLAUSE where IF the first part is NOT TRUE, the second one is NOT executed?
Ideally, because @UserType is NOT ‘FaceBook’, we should NOT try to calculate the second part of that line (the CAST).
While sql does do short circuiting (the feature that allows a language to only evaluate one part of a condition), it does not do it in the same way as other languages.
Sql Server uses an optimizer to build an execution plan for a query. The optimizer looks at the query, and tries to build it in the most efficient way possible. Most of the time it optimizes for the estimated number of results or best index use: it wants to keep fewer records locked at a time and fewer records in memory at a time. But when sets from two conditions are about the same size or match similar indexes, it can also mean things like checking indexed columns in the where clause before non-indexed columns, or making small (and therefore fast) comparisons like bits or integers before longer (and therefore slower) comparisons (like string matches).
In this case, your best chance is to treat both sides as a text type (varchar, nchar, etc) and use that for your match. It will be slower, but you must always code for correctness first, and performance second.
This should work: