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))
CodePudding user response:
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
CodePudding user response:
- 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.
- Some people suggest making query parameters
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...
}