我在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。
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上搜索我找不到一个优雅的解决方案。
任何人都可以提供帮助吗?
答案 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;
另见: