如何使用来自HTTP FORM的值列表执行类似于“NOT IN”的WHERE?

时间:2012-04-27 18:08:39

标签: sql sql-server forms

我在C#中开发了Web应用程序,其中一个页面显示了SQL查询的输出;查询是对商店过程的linq调用,我使用的是SQL Server 2008。

其中一列显示与结果行关联的标签;在同一页面上显示一个复选框列表,每个复选框对应一个标签,如果用户打开或关闭一个或多个复选框,我想过滤查询。

我最简单的SQL解决方案将是“NOT IN”,如下所示:

select * from [mytable] where [tags] not in ('tag1','tag2, etc...)

鉴于我将FORM POST转换为带逗号分隔值的字符串。 例如:

string tags = ParseFormAndConvertCheckBoxToCSV(Page.Request.Form);
string sqlcmd = "select * from [mytable] where [tags] not in (" + tags + ")";

但我不想动态构建SQL,因为据我所知that would be bad

我可以想象splitting the string with comma separated list of values in SQL nd store the values into a in-memory table的几种方式:

declare @tagscsv nvarchar(MAX)
declare @notags TABLE(Value nvarchar(50))

set @tagscsv = 'taxi,ivf'

Declare @x XML 
select @x = cast('<A>'+ replace(@tagscsv,',','</A><A>')+ '</A>' as xml)

insert into @notags
select t.value('.', 'nvarchar(50)') as v from @x.nodes('/A') as x(t)

select * from [mytable] where [tags] not in (select * from @notags)

......但这听起来像是一个肮脏的把戏。

对我来说,这看起来应该是一个非常普遍的情况,我发现过去很多人都遇到过这个问题,但在google上搜索我找不到一个优雅的解决方案。

任何人都可以提供帮助吗?

1 个答案:

答案 0 :(得分:1)

编辑:错过了存储过程部分。 使用存储过程,您没有很多选项。我通常做你做的,拆分逗号分隔字符串并将值保存到临时表(或表变量)。

CREATE PROCEDURE SplitAndStuff
    @List nvarchar(MAX) = NULL,
    @SplitOn nvarchar(5) = ','  --This can be replaced with a literal if it is always a comma.
AS
BEGIN
    DECLARE @Pos int;
    DECLARE @SplitOnLength int;
    DECLARE @Results TABLE (value nvarchar(MAX))
    SET @SplitOnLength = DATALENGTH(@SplitOn) / 2;

    IF (RIGHT(@List, @SplitOnLength) <> @SplitOn) SET @List = @List + @SplitOn; --Add trailling split string if there is not one already.

    SET @Pos = CHARINDEX(@SplitOn, @List, 1)                                    --Initalize for loop.  (The starting position returned is 1-based, not 0-based.)

    WHILE @Pos > 0
    BEGIN
        INSERT INTO @Results (value) SELECT CAST(SUBSTRING(@List,1,@Pos-1)AS int);

        SET @List = SUBSTRING(@List, @Pos+@SplitOnLength, DATALENGTH(@List) / 2);
        SET @Pos = CHARINDEX(@SplitOn, @List, 1);
    END
END
GO

如果您的存储过程没有做任何其他事情(除了查找),您可以使用我原来的LINQ答案:

由于您使用的是LINQ,因此需要拆分tagscsv并使用生成的数组执行“where in”查询:

string[] tags = tagscsv.Split(',');
var output = from q in db.Table where !tags.Contains(q) select q;

另见: