如何实施接受动态搜索条件的存储过程?

时间:2013-04-22 11:35:09

标签: sql sql-server-2008 stored-procedures

假设我有下表(TestTable):

  

ID,SystemID,UserID (所有列的类型均为int)

我想编写一个应该接受字符串参数的存储过程;它的值如((5和6)或7)可返回应用以下查询的所有用户:

Select * From TestTable Where SystemID = 5

Intersect

Select * From TestTable Where SystemID = 6

以上结果是 union

Select * From TestTable Where SystemID = 7

SP必须接受任何组合,例如(((4或5)和6)或8)(((5或9)或8)和10) ..等等

我该如何实现?

更新:我的问题不是如何拆分字符串..但是如何让动态sql实现它的逻辑意义

3 个答案:

答案 0 :(得分:1)

DECLARE @param NVARCHAR(MAX) = N'4 or 5 and 6 or 8 and 10';


DECLARE 
  @sql NVARCHAR(MAX) = N'', 
  @q NVARCHAR(MAX) = N'SELECT UserID FROM dbo.TestTable WHERE SystemID = ';

SELECT @sql = @q + REPLACE(REPLACE(@param, ' or ', '
   UNION ALL ' + @q),
 ' and ', '
   INTERSECT ' + @q);

PRINT @sql;
-- EXEC sp_executesql @sql;

结果:

SELECT UserID FROM dbo.TestTable WHERE SystemID = 4
   UNION ALL SELECT UserID FROM dbo.TestTable WHERE SystemID = 5
   INTERSECT SELECT UserID FROM dbo.TestTable WHERE SystemID = 6
   UNION ALL SELECT UserID FROM dbo.TestTable WHERE SystemID = 8
   INTERSECT SELECT UserID FROM dbo.TestTable WHERE SystemID = 10

现在,无论这个查询是否产生您实际效果的结果,我都不知道,但我相信它符合上述要求。

答案 1 :(得分:-1)

试试这个......我几乎没有改变Aaron Bertrand的询问。

 DECLARE @param NVARCHAR(MAX) = N'(((4 or 5) and 6) or 8)';
    DECLARE   @sql NVARCHAR(MAX) = N'', 
      @q NVARCHAR(MAX) =  N'SELECT * FROM dbo.TestTable WHERE SystemID = ',
      @paranth NVARCHAR(100) = substring(@param,0,PATINDEX('%[0-9]%',@param));
      set @param =substring(@param,PATINDEX('%[0-9]%',@param),len(@param)-PATINDEX('%[0-9]%',@param))

    SELECT @sql = @q + REPLACE(REPLACE(@param, ' or ', '
       UNION ALL ' + @q),
     ' and ', '
       INTERSECT ' + @q);
       set @sql=@paranth+@sql
       if (isnull(@paranth,'')<>'')
        set @sql=@sql+')'

    PRINT @sql;

答案 2 :(得分:-2)

您可以在SP中使用CSV到整数表值函数。首先,您必须首先创建CsvToInt函数。然后,您可以在存储过程中使用它将参数转换为整数列表。正如所指出的,这仅适用于动态搜索条件的“或”组件。

您可以将其与EXECsp_executesql结合使用。这将允许您添加sql作为参数。

SET @myBaseQuery = 'SELECT * FROM TestTable WHERE SystemId = ' + @myParam
EXECUTE(@myBaseQuery)

SELECT * FROM TestTable WHERE SystemID IN (SELECT IntValue FROM dbo.CsvToInt('2,3,4,5,6'))
-- use your parameters

CREATE FUNCTION [dbo].[CsvToInt] ( @Array VARCHAR(1000)) 
RETURNS @IntTable TABLE 
    (IntValue INT)
AS
BEGIN
    DECLARE @separator CHAR(1)
    SET @separator = ','
    DECLARE @separator_position INT 
    DECLARE @array_value VARCHAR(1000) 
    SET @array = @array + ','
    While patindex('%,%' , @array) <> 0 
    BEGIN
      SELECT @separator_position =  patindex('%,%' , @array)
      SELECT @array_value = LEFT(@array, @separator_position - 1)
        INSERT @IntTable
        VALUES (CAST(@array_value AS INT))
      SELECT @array = stuff(@array, 1, @separator_position, '')
    END
    RETURN
END

CsvToInt函数取自http://www.summit-pro.com/blog/2010/05/18/csv-list-to-int-sql-function/