尝试忽略 Winforms 中的空文本框以过滤 sql 搜索查询

Posted

技术标签:

【中文标题】尝试忽略 Winforms 中的空文本框以过滤 sql 搜索查询【英文标题】:Trying to ignore null textboxes in Winforms to filter sql search query 【发布时间】:2021-07-21 21:08:41 【问题描述】:

目前我正在尝试保留一个持久的 where 子句,然后通过附加是否存在每个文本框来附加额外的过滤器。问题是这给了我一个很好的命令,但是在尝试使用该命令时我仍然收到错误。如果有任何简化或指导,将不胜感激!

if (string.IsNullOrEmpty(make) && (string.IsNullOrEmpty(model)) && (string.IsNullOrEmpty(color)) && (string.IsNullOrEmpty(min)) && (string.IsNullOrEmpty(max)) && (string.IsNullOrEmpty(miles)))
            
                SqlCommand updateDataGridViewCmd = new SqlCommand("select m.make, m.model, car.price, color.color, car.mileage, carlot.lotid, car.pic from car join makemodel as m ON m.mmid = car.mmid join color ON  car.colorid = color.colorid join carlot ON  carlot.carid = car.carid; ", sqlCon);

                dt.Load(updateDataGridViewCmd.ExecuteReader());
                dataGridView1.DataSource = dt;
            
            else
            
                StringBuilder sqlCommandText = new StringBuilder();
                sqlCommandText.Append("select m.make, m.model, car.price, color.color, car.mileage, carlot.lotid, car.pic from car join makemodel as m ON m.mmid = car.mmid join color ON  car.colorid = color.colorid join carlot ON  carlot.carid = car.carid where");
                string CommandText = sqlCommandText.ToString();

                SqlCommand updateDataGridViewCmd = new SqlCommand(CommandText, sqlCon);
                updateDataGridViewCmd.Parameters.AddWithValue("@make", make);
                updateDataGridViewCmd.Parameters.AddWithValue("@model", model);
                updateDataGridViewCmd.Parameters.AddWithValue("@min", min);
                updateDataGridViewCmd.Parameters.AddWithValue("@max", max);
                updateDataGridViewCmd.Parameters.AddWithValue("@mileage", miles);
                updateDataGridViewCmd.Parameters.AddWithValue("@color", color);



                if (!string.IsNullOrEmpty(make))
                
                    sqlCommandText.Append(" m.make = @make");
                    CommandText = sqlCommandText.ToString();
                

                if (!string.IsNullOrEmpty(model))
                
                    sqlCommandText.Append(" OR m.model = @model");
                    CommandText = sqlCommandText.ToString();
                

                if (!string.IsNullOrEmpty(min))
                
                    sqlCommandText.Append(" car.price between @min");
                    CommandText = sqlCommandText.ToString();
                    if (!string.IsNullOrEmpty(max))
                    
                        sqlCommandText.Append(" AND @max");
                        CommandText = sqlCommandText.ToString();

                    
                    else 
                    
                        sqlCommandText.Append(",");
                        CommandText = sqlCommandText.ToString();
                    
                

                if (!string.IsNullOrEmpty(color))
                
                    sqlCommandText.Append(" color.color = @color,");
                    CommandText = sqlCommandText.ToString();
                

                if (!string.IsNullOrEmpty(miles))
                
                    sqlCommandText.Append(" car.price <= @mileage");
                    CommandText = sqlCommandText.ToString();
                
                sqlCommandText.Append(";");
                CommandText = sqlCommandText.ToString();
                dt.Load(updateDataGridViewCmd.ExecuteReader());
                dataGridView1.DataSource = dt;
            

                
        
    

错误:

【问题讨论】:

这里可以使用任何 ORM 吗?在处理动态查询时会有很大帮助 什么错误?请添加更多信息,否则只是一个猜谜游戏 可能是因为您没有使用and, or 之一链接条件 您生成的 SQL 存在大量语法错误。在调试器中看一下 命令是什么? 【参考方案1】:

您可能会看到一个错误,因为您没有使用andor 加入您的条件字符串。 如果这里没有 ORM 选项(这在组合查询时可能很实用),您可以使用 where 1=1 结束基本查询,然后使用 and x=...or x=... 链接其他条件 在应用所有过滤器后,您也可以只设置一次CommandText = sqlCommandText.ToString();

【讨论】:

对品牌和型号进行了测试,得到了select m.make, m.model, car.price, color.color, car.mileage, carlot.lotid, car.pic from car join makemodel as m ON m.mmid = car.mmid join color ON car.colorid = color.colorid join carlot ON carlot.carid = car.carid where m.make = @make OR m.model = @model;,它存储在命令文本中,这不是一个有效的查询吗? 我重新编辑以在命令文本中显示文本 WHERE 1=1 是不必要的。在List&lt;string&gt; 中捕获条件,然后将它们组合起来,例如string.Join(" OR ", myConditions) @Eric 但他们并不都是andor。它们混合在一起。使用字符串将它们全部连接起来。加入将导致值用相同的分隔符分隔 string.Join(" ", myConditions) 其中myConditions 包括and/or 术语。混合使用或不使用括号来指定操作顺序在一般意义上是没有用的。【参考方案2】:

认为这是一个伪代码。我在这个编辑器中从头开始写了它。基本上,与其处理无穷无尽的条件,不如创建一个对象,将您的条件分组,然后对这些对象实例的输出进行分组。它应该为您构建一个完美的过滤器。

public class WhereToken


    private List<SqlParameter> _localColl;
    // privates declared here
    privat bool _between;

    public WhereToken (string col, object[] values, SqlDbType t, SqlParameterCollection paramColl)
    
       // assign privates here
    

    public WhereToken (string col, object value1, object value2, SqlDbType t, SqlParameterCollection paramColl)
    
        // assign privates here
        _between = true;
        _values = new object[]value1, value2;
    

    public string Write()
    
        if (values.Length = 0)
            return null;
        _localColl = new List<SqlParameter>();

        var b = new StringBuilder();
        b.Append("(");
            for (int i = 0; l < _values.Length; i++)
            
                var pName = string.Concat("@", col, i); 
                var p = new SqlParameter(pName, values[i], _sqlType);
                b.Append(_col);

                if (_between)
                    b.Append(" BETWEEN ");
                else
                    b.Append("=");

                b.Append(pName);
                if (i < values.Length - 1)
                
                    if (_between)
                        b.Append(" AND ");
                    else
                       b.Append(" OR ");
                
            

        b.Append(")");

        foreach(var pp in _localColl)
            _paramColl.Parameters.Add(pp);

        return b.ToString();

    



// In code

var tokens = new List<WhereToken>();
var wt1 = new WhereToken("make", new string[]txt.Make.Text, SqlDbType.NVarchar, sqlCommand.ParameterCollection);
tokens.Add(w1);

// in real life, you need to check if both values present, etc
var wt2 = new WhereToken("year", Convert.ToInt32(txt.YearMin.Text), Convert.ToInt32(txt.YearMax.Text), SqlDbType.Int, sqlCommand.ParameterCollection);
tokens.Add(w2);

// more items here . . . . 

var builder = new StringBuilder(yourMainSQLSelect); 
builder.Append(" WHERE 1=1"); // 1=1 what if the tokens don't generate
for (int i = 0; i < tokens.Length; i++)

    string token = tokens[i].Write();
    if (token == null) continue;

    builder.Append(" AND ");
    builder.Append(token);


sqlCommand.CommandText = builder.ToString();

这段代码 ^^ 应该为您构建类似的东西

... where 1=1 and make=@make0 and (year BETWEEN @year0 AND @year1)

当然,您可以改进有关如何从WhereToken 解析和输出的内置逻辑。但这是适合您的概念 - 解析小标记然后加入它们。不要尝试为所有输入字段构建逻辑

【讨论】:

【参考方案3】:

在我看来,如果某些输入字符串为空或空,您想用谓词扩展 WHERE。

让我们忽略空字符串,所以我不必写:is null or empty string

SELECT ... FROM TABLECUSTOMERS WHERE <predicate1> OR <predicate2> OR ...

您添加的谓词取决于哪些输入字符串为空。在我看来,大多数时候,如果输入字符串为空,你想省略谓词。像这样的:

if (inputStringName != null)

   strBuilder.Append("OR CustomerName = @Name")

这与:

OR (@Name != null AND @Name == CustomerName)

如果你想使用 AND 而不是 OR:

AND (@Name == null OR @Name == CustomerName)

所以我的建议是:创建一个包含所有可能变量的 SQL 命令,然后更改命令以使谓词也测试参数是否等于 null

SELECT ... FROM car
JOIN ...
WHERE ( NOT @Make = NULL AND @Make = m.Make)
   OR ( NOT @Model = NULL AND @Model = m.Model)
   OR ( NOT @Mileage = NULL AND @Mileage > car.Mileage)

因此,在使用参数之前,请检查参数是否为空。取决于您是要附加 AND 还是 OR 使用类似:

或(不是@Value = NULL AND @Value = car.MyValue) AND(@Value = NULL 或 @Value = car.MyValue)

我的SQL有点生疏,一直在用实体框架,所以对NOT =有点不确定,可能这个应该是!=,可能括号应该多一些,不过我猜你明白要点。

为了避免必须检查空字符串:在您之前将空字符串设为空AddWithValue

【讨论】:

以上是关于尝试忽略 Winforms 中的空文本框以过滤 sql 搜索查询的主要内容,如果未能解决你的问题,请参考以下文章

忽略 SQL 中的空绑定变量

Linux/bash 解析文本输出,选择字段,仅忽略一个字段中的空值

C# winforms:将可空类型绑定到其他属性(不是文本)时出错

删除暴露过滤器中的空选项

将列分组为一行,忽略 postgreSQL 中的空值

在 C# winforms 应用程序中使用文本框过滤 Treeview