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。诀窍是,当语言期望表达式时,不能用替代语句 - 此外,除了某些特殊用法,您不能将过程语句放在表达式的中间(除了可以评估为一个表达式,例如单列和单行SELECT
或EXISTS
)。表达式可以包含包含表达式的表达式。它们就像一棵树,一直倒塌。
想想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
的版本不使用BEGIN
和END
和接受一个声明 - 这种形式导致混乱和错误。我每次都使用BEGIN
和END
,这看起来像是一种痛苦,直到你发现多少时间和精力为你节省了大量的时间......
你可以试试这个,不需要提供病例,取决于@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
立即跳转到推荐动态SQL并不好,初学者几乎总是迷失在动态SQL中并滥用它 - 最好的是他们甚至不知道这些事情是可能的,直到他们更有经验。 – ErikE 2014-09-04 05:21:13
+1奇妙的配方 - 谢谢! – 2014-09-04 05:27:46
IF ELSE ...这是多么简单......我也不知道这些差异......现在感到很惭愧......:'(谢谢!!!! – Raccoon 2014-09-04 05:30:15
@Raccoon请不要感到羞愧。我的希望不仅仅是解决这个问题,而是为了帮助你更深入地思考T-SQL是如何构建的,以便你不仅可以解决这个问题,而且可以解决更先进的问题, – ErikE 2014-09-04 05:54:52