2013-07-19 9 views
3

Я пытаюсь запросить существующую базу данных доступа и позволить пользователю выбирать несколько значений для предложения WHERE. Я использую этот код обнаружен на этом сайте любезно пользователя Mark Брэкетом:Запрос базы данных с неизвестным количеством параметров

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 Tags.

ответ

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 как «Выберите * 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 ....)" если нет параметров переменной WHERE будет = ""

2

Try, как

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 имеет значение null, то все теги возвращаются.

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 ...' ... –