根据复选框的选择标准动态构建sql语句

时间:2011-08-07 19:05:19

标签: c# sql-server-2005 dynamic

我有一个.aspx页面,其中的产品在SQL Server 2005数据库中分为不同的类别。

用户应该能够从任何组合中进行选择。例如,从COLOR类别中选择“Beige”和“Black”,从STYLES类别中选择“Tapestry”,只能选择带有Beige + Tapestry和Black + Tapestry的产品。

我正在考虑使用WHERE子句来检查: 如果检查了任何COLOR复选框,则使用WhereCluaseColor + =复选框值,将这些复选框的值构建到'WhereClauseColor'字符串变量中;

如果检查了任何STYLES复选框,则使用另一个名为WhereClauseStyles的变量 - 就像在Color类别中一样。

最后,构建一个名为WhereClause的sql字符串: 如果WhereClauseColor!=“”则WhereClause + = AND''''字段在db中包含WhereClauseColor;

对于样式来说类似的东西。

但我没有运气。可能我需要一种完全不同的方法。太糟糕了,客户希望产品成为复选框,以允许在每个类别下进行多项选择。

WhereClause = "SELECT * FROM [xxxx] WHERE 0 = 1";
/////COLORS
// if (Request.Form["color_gold"] != null) { WhereClause += " OR  xxx.color = 'gold'"; }//// OLD CODE. . 08/04/11
if (Request.Form["color_spice"] != null) { WhereClause += " OR  CONTAINS (xxxx.color,'spice')"; }/// ## NEW CODE: NOTE CONTAINS. . 08/04/11

5 个答案:

答案 0 :(得分:0)

您是否曾尝试在SSMS中构建所需的SQL选择查询以获得正确的语法,以便在您开始构建动态查询时至少现在您的目标是什么?这就是我要这样做的方式。

您也可以在SQL中使用临时表执行所有操作,其中第一个查询采用第一个选中的复选框(作为params传递给存储过程,并在下一节中处理下一组复选框)你的存储过程。

答案 1 :(得分:0)

我不确切知道您使用Request.Form的原因。像if (chkSpice.Checked)这样的东西会更具可读性。

如果您必须将SQL保留在代码中,并且不能使用存储过程,那么这是您可以执行此操作的一种方法。您不接受用户输入并在SQL中传递它,因此没有SQL注入风险。

如果您知道在数据库中命名的样式和颜色,SQL IN运算符会更有效。

string styles = String.Empty;
string colors = String.Empty;

if (chkTapestry.Checked)
    styles = "'Tapestry'";
else if (chkRug.Checked)
    styles += ",'Rug'";


if (chkBlack.Checked)
    colors = "'Black'";
else if (chkBeige.Checked)
    colors += ",'Beige'";

string sql = "SELECT * FROM [X]";

if (styles.Length > 0 && colors.Length > 0)
    sql += String.Format(" WHERE [Style] IN ({0}) AND [Color] IN ({1})", styles, colors);
else if (styles.Length > 0)
    sql += String.Format(" WHERE [Style] IN ({0})", styles);
else if (colors.Length > 0)
    sql += String.Format(" WHERE [Color] IN ({0})", colors);

以上是一种相当手动的方法来组合样式和颜色,并使用令人遗憾的样式和颜色名称的硬编码。更好的设计可能是:

  1. 从数据库中选择所有颜色。将它们存储在DataTable中。
  2. DataBind将颜色DataTable绑定到CheckBoxList控件以显示页面上的颜色。
  3. 从数据库中选择所有样式。将它们存储在另一个DataTable中。
  4. DataBind样式DataTable到CheckBoxList控件以显示页面上的样式。
  5. 然后,在PostBack上:

    1. 使用数据库中的值重新加载颜色DataTable。接受自页面呈现以来颜色列表发生更改的小风险,或将DataTable存储在回发后的Session变量中以降低风险。
    2. 重新加载样式DataTable。
    3. 在for循环中迭代您的颜色CheckBoxList项。对于所选的每个项目,使用for循环索引从DataTable中检索相同的行索引。从DataRow获取颜色名称,并将其添加到要在WHERE子句的Color IN (...)部分中使用的颜色列表中。这可确保您使用数据库中的值,而不是可能被用户篡改的值。
    4. 在for循环中迭代你的样式CheckBoxList项目,做与颜色相同的事情。
    5. 像我在示例代码中那样组装WHERE子句。
    6. 对您的数据库执行查询并处理结果集。
    7. 示例代码:

      protected DataTable dtColors
      {
          get
          {
              if (Session["fabrics-dtColors"] == null)
                  Session["fabrics-dtColors"] = FetchDataTable("SELECT DISTINCT Color FROM X ORDER BY Color");
              return (DataTable)Session["fabrics-dtColors"]; 
          }
      }
      
      protected DataTable dtStyles
      {
          get
          {
              if (Session["fabrics-dtStyles"] == null)
                  Session["fabrics-dtStyles"] = FetchDataTable("SELECT DISTINCT Style FROM X ORDER BY Style");
              return (DataTable)Session["fabrics-dtStyles"]; 
          }
      }
      
      protected void Page_Load(object sender, EventArgs e)
      {
          if (!IsPostBack)
          {
              cblColors.DataSource = dtColors;
              cblColors.DataBind();
      
              cblStyles.DataSource = dtStyles;
              cblStyles.DataBind();
          }
      }
      
      protected void btnSearch_OnClick(object sender, EventArgs e)
      {
          string colors = String.Empty;
          string styles = String.Empty;
          string sql = "SELECT * FROM [X]";
      
          if (cblColors.SelectedIndex > -1)
          {
              for (int i = 0; i < cblColors.Items.Count; i++)
              {
                  if (cblColors.Items[i].Selected)
                  {
                      colors += String.Format("'{0}',", dtColors.Rows[i][0]);
                  }
              }
      
              colors = colors.TrimEnd(',');
          }
      
          if (cblStyles.SelectedIndex > -1)
          {
              for (int i = 0; i < cblStyles.Items.Count; i++)
              {
                  if (cblStyles.Items[i].Selected)
                  {
                      styles += String.Format("'{0}',", dtStyles.Rows[i][0]);
                  }
              }
      
              styles = styles.TrimEnd(',');
          }
      
          if (styles.Length > 0 && colors.Length > 0)
              sql += String.Format(" WHERE [Style] IN ({0}) AND [Color] IN ({1})", styles, colors);
          else if (styles.Length > 0)
              sql += String.Format(" WHERE [Style] IN ({0})", styles);
          else if (colors.Length > 0)
              sql += String.Format(" WHERE [Color] IN ({0})", colors);
      
          GetSearchResults(sql);
      }
      

答案 2 :(得分:0)

private List<string> arrColors = new List<String>();
private List<string> arrStyles = new List<String>();   

if (Request.Form["color_spice"] != null) { 
  arrColors.Add("spice"); }/// ## NEW CODE: NOTE CONTAINS. . 08/04/11

if (Request.Form["color_gold"] != null) { arrColors.Add("gold"); }

string sql = "select * from ado_products_fabrics where [color] in('";
       sql += string.Join("','", this.arrColors.ToArray());
       sql += "')";
       sql += " AND [style] in('";
       sql += string.Join("','", this.arrStyles.ToArray());
       sql += "')";

WhereClause = sql;/

答案 3 :(得分:0)

我一直在研究一个名为QBuilder的库,以使这种动态sql生成更容易一些。它可能对你有用。

http://qbuilder.codeplex.com/

答案 4 :(得分:-1)

从您的各种选择中构建应用程序代码中的表:SelectedColors,Selected Styles,....然后将它们作为参数传递给在WHERE子句中使用它们的存储过程:

where ( Color in (select Color from SelectedColors) or
     not exists ( select Color from SelectedColors ) ) and ...

我假设如果没有对给定类别进行选择,例如打印比例,您要接受所有值。

这将允许您进行多项选择并防止SQL注入攻击。