SQL Server存储过程 - 通过CASE执行不同的查询

问题描述:

我有两个存储过程的参数。根据Searching_Condition的值,必须搜索正确的列。在伪代码格式中,它应该是这样的SQL Server存储过程 - 通过CASE执行不同的查询

//CASE @Search_Condition 
// WHEN 'UserID' THEN SELECT * FROM user_table WHERE UserID LIKE '@Keywords' 
// WHEN 'UserName' THEN SELECT * FROM user_table WHERE UserName LIKE '@Keywords' 
// WHEN 'UserAddress' THEN SELECT * FROM user_table WHERE UserAddress LIKE '@Keywords' 

以下是我正在处理的代码,以及哪里被卡住了。它应该很简单,但是对于不熟悉SQL Server的人来说,我很苦恼,并且SQL Server中的CASE不能像我认为的那样工作。

谢谢!

CREATE PROCEDURE [dbo].[USP_SP_NAME] 
    @Searching_Condition NVARCHAR(100), 
    @Keywords NVARCHAR(100) 
AS 
SET NOCOUNT ON 
SET LOCK_TIMEOUT 3000 
SET XACT_ABORT ON 
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 

BEGIN TRY 
    SELECT 
     CASE WHEN 
      @Searching_Condition = 'user_id' THEN 
       (select count(*) from user_table) 
       WHEN 
        @Searching_Condition = 'user_name' THEN 
        (select * from user_table) 
     END 
END TRY 

的关键概念,这将有助于你得到这个权利是表达声明之间的差异。

声明是程序性的,并指导控制流程。你可以考虑一个从语句到语句的指令指针,并且每条语句都与其他语句隔离(尽管它们可以选择在它们之后执行的语句)。他们可以被认为是动词

表达式可以简化为一个值 - 一个标量值,一个字符串甚至一个行集 - 但表达式不会执行任何操作。他们可以被认为是名词。这些名词不能单独存在,它们必须在声明的背景下。

SQL Server中的CASE语句是表达式。这不是像Select Case这样的程序性声明,例如,Visual Basic。诀窍是,当语言期望表达式时,不能用替代语句 - 此外,除了某些特殊用法,您不能将过程语句放在表达式的中间(除了可以评估为一个表达式,例如单列和单行SELECTEXISTS)。表达式可以包含包含表达式的表达式。它们就像一棵树,一直倒塌。

想想EXECUTE dbo.MyStoredProcedure (8 + @@SPID)/2中的部件:这是一个单独的语句,带有一个参数表达式,由三个子表达式组成,这些子表达式以特定的顺序进行评估,并解析为单个值,该值作为参数存储过程。你不能自己执行(8 + @@SPID)/2,因为它不是一个声明。 (不要介意表达式很愚蠢,只是举例)。

我曾经说过,在某些情况下,行集可以是值,但几乎所有表达式的预期类型都是单个值 - 而不是行集。这就是在这里发生的问题 - 您的外部SELECT声明期望单个行中第一列的定义值为单个值(因为您没有FROM子句),但您尝试提供一个完整的行集您的搜索条件是'user_name'

您可以通过完全放弃CASE并使用IF来解决此问题 - 因为IF是一个程序性声明。

CREATE PROCEDURE [dbo].[USP_SP_NAME] 
    @Searching_Condition NVARCHAR(100), 
    @Keywords NVARCHAR(100) 
AS 
SET NOCOUNT ON; 
SET LOCK_TIMEOUT 3000; 
SET XACT_ABORT ON; 
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

BEGIN TRY 
    IF @Searching_Condition = 'user_id' BEGIN 
     select count(*) from user_table; 
    END 
    ELSE IF @Searching_Condition = 'user_name' BEGIN 
     select * from user_table; 
    END; 
END TRY; 

我主张避免IF的版本不使用BEGINEND和接受一个声明 - 这种形式导致混乱和错误。我每次都使用BEGINEND,这看起来像是一种痛苦,直到你发现多少时间和精力为你节省了大量的时间......

+0

+1奇妙的配方 - 谢谢! – 2014-09-04 05:27:46

+0

IF ELSE ...这是多么简单......我也不知道这些差异......现在感到很惭愧......:'(谢谢!!!! – Raccoon 2014-09-04 05:30:15

+1

@Raccoon请不要感到羞愧。我的希望不仅仅是解决这个问题,而是为了帮助你更深入地思考T-SQL是如何构建的,以便你不仅可以解决这个问题,而且可以解决更先进的问题, – ErikE 2014-09-04 05:54:52

你可以试试这个,不需要提供病例,取决于@Searching_Condition值改为:

CREATE PROCEDURE [dbo].[USP_SP_NAME] 
    @Searching_Condition NVARCHAR(100), 
    @Keywords NVARCHAR(100) 
AS 
SET NOCOUNT ON 
SET LOCK_TIMEOUT 3000 
SET XACT_ABORT ON 
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 

BEGIN TRY 
    exec('Select * from user_table WHERE'+ @Searching_Condition+' LIKE '+ @Keywords); 
END TRY 
+0

立即跳转到推荐动态SQL并不好,初学者几乎总是迷失在动态SQL中并滥用它 - 最好的是他们甚至不知道这些事情是可能的,直到他们更有经验。 – ErikE 2014-09-04 05:21:13