2013-06-21 130 views
1

我创建了一个表单,用户可以使用它来搜索事务。这是形式的图片:ASP.NET - 实现搜索功能和SQL

enter image description here

现在,总价下拉列表中有成员:

  1. 任何代价
  2. 确切数额
  3. 以下金额
  4. 以上金额

货币下拉列表中有成员:

  1. 任何货币
  2. EUR
  3. 美元
  4. GBP

交易日下拉列表中有成员:

  1. 任何日期
  2. 准确日期
  3. 以下日期
  4. 以上日期

交易状态下拉列表中有成员:

  1. 任何状态
  2. 有效
  3. 过期
  4. 付费

所有细节正在从表中取出名为付款

有人可以帮我我怎么去付款表中搜索?使用一条SQL语句可以满足所有不同的可能性吗?或者我必须使用多个SQL语句?有人可以给我一个可用于满足不同可能性的SQL语句模板吗?请帮忙,因为SQL不是我最强的一点。谢谢:)

回答

1

UPDATE:修改下面的代码,以允许范围(包括无界范围)

一个存储过程可以很容易地处理的查询,如此,如果正确地明白。只需检查NULL即可使参数可选。如果参数是NULL,请不要根据它进行查询。

CREATE PROCEDURE schema.FindPayments 
(
    @MinPrice double = NULL, 
    @MaxPrice double = NULL, 
    @Currency char(3) = NULL, 
    @MinTranDate datetime = NULL, 
    @MaxTranDate datetime = NULL, 
    @TranStatus int = NULL 
) 
AS BEGIN 

    SELECT  * 
    FROM  Payments 
    WHERE  (
         @MinPrice IS NULL 
        OR TotalPrice >= @MinPrice 
       ) 
      OR (
         @MaxPrice IS NULL 
        OR TotalPrice <= @MaxPrice 
       ) 
      OR (
         @Currency IS NULL 
        OR Currency = @Currency 
       ) 
      OR (
         @MinTranDate IS NULL 
        OR TranDate >= @MinTranDate 
       ) 
      OR (
         @MaxTranDate IS NULL 
        OR TranDate <= @MaxTranDate 
       ) 
      OR (
         @TranStatus IS NULL 
        OR TranStatus = @TranStatus 
       ) 
END 

现在您还可以从这个代码存储过程中无论是DBNull.Value通过为未指定的参数,或者因为我分配NULL为默认为所有paramters,你可以通过选定的参数。

SqlCommand l_findPayments = new SqlCommand("FindPayments", new SqlConnection("...")); 
l_findPayments.CommandType = CommandType.StoredProcedure; 

if (l_totalPriceComparison == "Exact Amount") 
{ 
    findPayments.Parameters.Add(new SqlParameter("@MinPrice", l_price)); 
    findPayments.Parameters.Add(new SqlParameter("@MaxPrice", l_price)); 
} 
else if (l_totalPriceComparison == "Below Amount") 
    findPayments.Parameters.Add(new SqlParameter("@MaxPrice", l_price)); 
else if (l_totalPriceComparison == "Above Amount") 
    findPayments.Parameters.Add(new SqlParameter("@MinPrice", l_price)); 
// "Any Price" will just leave the parameter 
// blank, so it will not filter on price 

// ... repeat for all params 

SqlDataReader l_result = l_findPayments.ExecuteReader(); 
+0

只有当用户选择“确切金额”,“确切日期”和除“任何状态”以外的任何状态时,这才起作用。例如,如果用户选择“低于金额”,则将无法返回准确的结果。 – HardCode

+0

@HardCode - 你是对的。一个简单的修改将允许你指定范围。一个确切的值'N'只会在'N到N'的范围内。对于像“任何状态”这样的东西,您只需将参数留空即可(因此返回任何状态)。 – JDB

3

最好的解决方案是根据在搜索表单中输入的字段,动态地将SQL查询字符串组装到C#代码中。

+0

我明白。它并没有跨越我的想法。这将是一个很好的选择。谢谢:) – Matthew

+0

并且不要忘记使用SQL参数来传递值。这避免了数据中的SQL注入攻击和撇号等问题。 –

+1

为什么动态查询参数化存储过程?存储的特效更快,对注入攻击更有抵抗力。 – JDB

0

一个好方法是使用您的数据库列名作为文本框/下拉ID。这样,您可以使用代码背后的ID属性,并且可以使用循环根据您的需要构建查询。假设你有这些建立在一个HTML表格或可循环类似其他一些结构...

string sql = "SELECT * FROM payments "; 
string field = ""; 
string value = ""; 
int parameter_count = 0; 
foreach(HtmlTableRow row in table.Rows) 
{ 
    foreach(Control c in row.Cells[1].Controls) 
    { 
     if (c is Textbox) 
     { 
      TextBox txt = c as TextBox; 
      if (txt.Text.Length > 0) 
      { 
       field = txt.ID; 
       value = txt.Text.Trim(); 
       if (parameter_count == 0) 
       { 
        sql += string.Format(" WHERE {0}='{1}' ", field, value); 
        parameter_count++; 
       } 
       else 
       { 
        sql += string.Format(" AND {0}='{1}' ", field, value); 
        parameter_count++; 
       } 
      } 
     } 
     else if (c is DropDownList) 
     { 
      DropDownList ddl = c as DropDownList; 
      if (ddl.SelectedValue.Length > 0) 
      { 
       field = ddl.ID; 
       value = ddl.SelectedValue.Trim(); 
       if (parameter_count == 0) 
       { 
        sql += string.Format(" WHERE {0}='{1}' ", field, value); 
        parameter_count++; 
       } 
       else 
       { 
        sql += string.Format(" AND {0}='{1}' ", field, value); 
        parameter_count++; 
        } 
       } 
      } 
     } 
    } 

现在,有一个明显的缺点简单地使用的String.format来构建查询,主要是您可以使用SQL注入。但是,我建议抛出string.Format部分,因为它们纯粹是为了示例的目的,以便您可以看到可以捕获字段/值的时刻,以便构建正确的参数化查询。这个更重要的部分就是包含这些语句的所有逻辑。它使您能够排除空白字段,并使其不会影响查询结果,除非它们具有值。希望这可以帮助!

+1

那么,您将如何构建一个具有动态列名称的防注入攻击解决方案? – JDB