简体   繁体   中英

Filtering MySQL query only when the filter values are not empty-string, white-space or null best practice

I want to filter the values here for say columnA, then by columnB etc, however I would like that if the filter valueA is simply an emptystring, that no filtering occurs and all values are accepted. The same for say valueB if that were empty then no filtering would occur.

This is a generic mysql query, where I would hope to only filter when the valueA or valueB (inclusive or) has a value that is not null, whitespace or empty string.

   using (var cmd = new MySqlCommand(
                    " SELECT columnA, columnB etc
                    " FROM table" +
                    " WHERE columnA = '" + valueA + "' " +
                    " THEN BY columnB = '" + valueB + "' " +
                    " GROUP BY columnA" +
                    " LIMIT 0, 100",
                    connection))
  • SQL, as a language, does not support dynamic predicates.
    • The ISO SQL design committee knows this, and they take glee from seeing us all suffer from having to use their horribly unergonomic and excessively verbose query language.
  • To have conditional predicates or dynamic predicates you will need to rebuild your query using some form of string concatenation.
    • Some people suggest making query parameters NULL able and abusing @value IS NULL OR [Column] = @value however this is (potentially) a horrible thing to do in production databases because (even as of 2021) I'm not aware of any major RDMBS handling this case properly and you end-up with very, very poor performing execution plans.

In your case, do something like this:

String sql;
List<MySqlParameter> parameters = new List<MySqlParameter>();

{
    StringBuilder sb = new StringBuilder( "SELECT columnA, columnB, FROM table" ).AppendLine();
    
    List<String> predicates = new List<String>();
    if( valueA != null )
    {
        predicates.Add( "columnA = @pA" );
        parameters.Add( new MySqlParameter( "@pA", valueA ) );
    }

    if( valueB != null )
    {
        predicates.Add( "columnB = @pB" );
        parameters.Add( new MySqlParameter( "@pB", valueB ) );
    }

    // etc
    
    if( predicates.Count > 0 )
    {
        _ = sb.AppendLine( "WHERE" );
        _ = sb.AppendLine( String.Join( " AND ", predicates ) );
    }

    //

    _ = sb.AppendLine( "ORDER BY foo GROUP BY bar LIMIT 0, 100" );

    sql = sb.ToString();
}

using( var cmd = new MySqlCommand( sql, connection ) )
{
    cmd.Parameters.AddRange( parameters );

    cmd.Execute...
}

You can use simple OR logic, and checking on the C# side for whitespace is easier

Note the use of parameterization to prevent SQL injection

Note the use of a multi-line string to make the query easier to read

const string query = @"
SELECT columnA, MAX(columnB) etc
FROM table
WHERE (columnA = @valueA OR @valueA IS NULL)
  AND (columnB = @valueB OR @valueB IS NULL)
GROUP BY columnA
LIMIT 0, 100;
";
using (var cmd = new MySqlCommand(query, connection))
{
    cmd.Parameters.AddWithValue("@valueA", string.IsNullOrWhiteSpace(valueA) ? (object)DBNull.Value : valueA);
    cmd.Parameters.AddWithValue("@valueB", string.IsNullOrWhiteSpace(valueB) ? (object)DBNull.Value : valueB);

Performance may not be great on large tables, so you may need to use completely separate queries

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM