2013-07-19 47 views
3

我试图查询现有的访问数据库并允许用户为WHERE子句选择多个值。我一直在使用此代码对用户马克布拉克特本网站礼貌发现:查询具有未知数量参数的数据库

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" }; 
string cmdText = "SELECT * FROM Tags WHERE Name IN ({0})"; 

string[] paramNames = tags.Select(
    (s, i) => "@tag" + i.ToString() 
).ToArray(); 

string inClause = string.Join(",", paramNames); 
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) { 
    for(int i = 0; i < paramNames.Length; i++) { 
     cmd.Parameters.AddWithValue(paramNames[i], tags[i]); 
    } 
} 

其中给出了这样的:

cmd.CommandText = "SELECT * FROM Tags WHERE Name IN (@tag0,@tag1,@tag2,@tag3)" 
cmd.Parameters["@tag0"] = "ruby" 
cmd.Parameters["@tag1"] = "rails" 
cmd.Parameters["@tag2"] = "scruffy" 
cmd.Parameters["@tag3"] = "rubyonrails" 

这工作出色,但我想下面的功能良好。如果用户决定不输入任何值(在本例中,如果标签数组为空),那么我希望返回所有结果。有效地只是一个SELECT * FROM标签。

回答

3

如何像

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" }; 
string cmdText = "SELECT * FROM Tags {0}"; 

string[] paramNames = tags.Select(
      (s, i) => "@tag" + i.ToString() 
     ).ToArray(); 

string cmdWhere = paramNames.Length > 0 ? String.Format("WHERE Name IN ({0})", string.Join(",", paramNames)) : ""; 
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, cmdWhere))) 
{ 
    for (int i = 0; i < paramNames.Length; i++) 
    { 
     cmd.Parameters.AddWithValue(paramNames[i], tags[i]); 
    } 
} 

因此,如果你没有参数,你在末尾没有添加where子句。

+0

这真是太好了,谢谢。我还可以看到,通过将我的cmdText设置为“Select * FROM Tags WHERE 1 = 1”,我可以在查询中使用这些多个参数子句中的几个,然后在“AND Name IN({0})”中使用您的代码。 – KorbenDallas

0

放在哪里子句的变量中,使的CommandText像cmd.CommandText = SELECT + WHERE 时:SELECT = "SELECT * FROM Tags" WHERE = "WHERE " + "Name IN (@tag0 ....)" 如果没有参数变量会在哪里=“”

2

尝试为

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" }; 
string cmdText = "SELECT * FROM Tags" ; 

string cond=" WHERE Name IN ({0})"; 

string[] paramNames = tags.Select(
    (s, i) => "@tag" + i.ToString() 
).ToArray(); 

if(paramNames.Length>0){ 
    string inClause = string.Join(",", paramNames); 
    cmdText=string.Concat(cmdText,string.Format(cond, inClause)); 
} 
using (SqlCommand cmd = new SqlCommand(cmdText) { 
    for(int i = 0; i < paramNames.Length; i++) { 
     cmd.Parameters.AddWithValue(paramNames[i], tags[i]); 
    } 
} 
+0

另一个很好的解决方案。谢谢。 – KorbenDallas

1

而不是每个项目一个参数,为什么不将它们连接起来?

我不知道这是否会在MS Access工作,但这里是我使用的MS SQL:

DECLARE @tagIds nvarchar(max) 

SELECT * FROM Tags where @tagIds is null or tagId IN (select number from dbo.iter_intlist_to_tbl(@tagIds)) 

所以@tagIds是一个逗号分隔的编号清单,我只是用函数解析它。如果@tagIds为空,则返回所有标记。

iter_intlist_to_tbl()功能如下:

CREATE FUNCTION [dbo].[iter_intlist_to_tbl] (@list nvarchar(MAX)) 
    RETURNS @tbl TABLE (listpos int IDENTITY(1, 1) NOT NULL, 
         number int NOT NULL) AS 
BEGIN 
    DECLARE @startpos int, 
      @endpos int, 
      @textpos int, 
      @chunklen smallint, 
      @str  nvarchar(4000), 
      @tmpstr nvarchar(4000), 
      @leftover nvarchar(4000) 

    SET @textpos = 1 
    SET @leftover = '' 
    WHILE @textpos <= datalength(@list)/2 
    BEGIN 
     SET @chunklen = 4000 - datalength(@leftover)/2 
     SET @tmpstr = ltrim(@leftover + 
        substring(@list, @textpos, @chunklen)) 
     SET @textpos = @textpos + @chunklen 

     SET @startpos = 0 
     SET @endpos = charindex(',' COLLATE database_default, @tmpstr) 

     WHILE @endpos > 0 
     BEGIN 
     SET @str = substring(@tmpstr, @startpos + 1, 
           @endpos - @startpos - 1) 
     IF @str <> '' 
      INSERT @tbl (number) VALUES(convert(int, @str)) 
     SET @startpos = @endpos 
     SET @endpos = charindex(',' COLLATE database_default, 
           @tmpstr, @startpos + 1) 
     END 

     SET @leftover = right(@tmpstr, datalength(@tmpstr)/2 - @startpos) 
    END 

    IF ltrim(rtrim(@leftover)) <> '' 
     INSERT @tbl (number) VALUES(convert(int, @leftover)) 

    RETURN 
END 
GO 

对分析逗号分隔列表的详细信息,请参阅http://www.sommarskog.se/arrays-in-sql-2005.html。虽然我想你会在MS Access不同的方法来做这

+0

谢谢你。它看起来很有趣,我会稍后再讨论它。 – KorbenDallas

1

我认为,如果任何标签的为空

if (@tag0 is null or @tag1 is null or @tag2 is null or @tag3 is null) 
begin 
    select * from tags 
end 
else 
    begin 
    SELECT * FROM Tags WHERE Name IN (@tag0,@tag1,@tag2,@tag3) 
end 
0

我已经修改了我现有的。这将工作。

string cmdText = "SELECT * FROM Tags "; 
     string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" }; 
     string where = null; 
     if (tags != null) 
     { 
      where = "WHERE Name IN ("; 
      foreach (string tag in tags) 
      { 
       where += "'" + tag + "',"; 
      } 
      where = where.TrimEnd(',') + ")"; 
     } 
     if (!string.IsNullOrEmpty(where)) 
     { 
      cmdText += where; 
     } 
+0

好吧,除了这个事实,这抛出的逻辑,计算'IN'子句中的值的数量基于数组中的值的数量持有搜索项的列表,*和*,你会最终就像'SELECT * FROM TagsWHERE Name IN ...'... –