SQL Where 子句 - 仅当某些 @Parameters 等于特定值时才执行

SF *_*per 4 sql t-sql

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  
Run Code Online (Sandbox Code Playgroud)

问题:
即使 UserType 是“LinkedIn”,第一个 WHERE 子句也会完全执行,并且 SQL 尝试将 @oAuthID 的值(在本例中为“aaaaaaa”)转换为 BIGINT。

问题:
我如何写一个 WHERE CLAUSE,如果第一部分不正确,第二部分不执行?
理想情况下,因为@UserType 不是'FaceBook',我们不应该尝试计算该行的第二部分(CAST)。

Joe*_*orn 5

虽然 sql 确实会进行短路(该功能允许一种语言只评估条件的一部分),但它的做法与其他语言不同。

Sql Server 使用优化器为查询构建执行计划。优化器查看查询,并尝试以最有效的方式构建它。大多数情况下,它会针对估计的结果数或最佳索引使用进行优化:它希望一次锁定更少的记录,并且一次保留更少的内存记录。但是当来自两个条件的集合大小相同或匹配相似的索引时,它也可能意味着在非索引列之前检查 where 子句中的索引列,或者更长的时间之前进行小(因此快速)比较,如位或整数(因此较慢)比较(如字符串匹配)。

在这种情况下,最好的机会是将双方视为文本类型(varchar、nchar 等)并将其用于匹配。它会更慢,但您必须始终首先编码正确性,然后才是性能。

这应该有效:

WHERE @oAuthID = CASE WHEN @UserType = 'Facebook' THEN Cast(FaceBookID as varchar(50))
                           WHEN @UserType = 'Twitter' THEN Cast(TwitterID as varchar(50))
                           WHEN @UserType = 'LinkedIn' THEN Cast(LinkedInID as varchar(50))
                           ELSE 'invalid user type' /* could use NULL here - as long as you'll never actually see a query with this value */
                           END
Run Code Online (Sandbox Code Playgroud)