I am trying to write simple filtering, where the user can input the column to filter and the value. The tricky part is dynamically choosing the column to filter.
I've found a couple solutions on the web and am not sure which to implement. My preference is to lean toward performance instead of maintainability. Any opinions would be greatly appreciated.
Let's assume I have a table "t", which has 5 VARCHAR columns: "c1", "c2", "c3", "c4", and "c5".
Solution 1 - The Easy Way
I could use Dynamic SQL. Something on the lines of:
DECLARE @sql VARCHAR(MAX) = 'SELECT * FROM t WHERE ' + @columnName + ' = ''' + @columnValue + ''';'
EXEC (@sql);
Which would come out to something like:
SELECT *
FROM t
WHERE c1 = 'asdf'
;
I don't want to use this solution for the following two reasons. I'm mainly including this as a simple point of reference before going down the rabbit hole.
- It does not guard against SQL injection.
- Even if I were to parameterize the columnValue, I would have 5 different execution plans cached for each of the 5 columns since you cannot parameterize @columnName.
Solution 2 - OR's
Could use a series of OR's with only two parameters. So let's say:
@columnName = 'c1'
@columnValue = 'asdf'
Then the SQL would become:
SELECT *
FROM t
WHERE (@columnName = 'c1' AND c1 = @columnValue)
OR (@columnName = 'c2' AND c2 = @columnValue)
OR (@columnName = 'c3' AND c3 = @columnValue)
OR (@columnName = 'c4' AND c4 = @columnValue)
OR (@columnName = 'c5' AND c5 = @columnValue)
OR (@columnName IS NULL AND 0 = 0)
;
I generally try to stay away using OR when possible. I remember reading somewhere it suffers from performance issues, but I'm no DBA and can't back that up. Thoughts?
Solution 3 - COALESCE
This solution relies on having a parameter for each column. So parameters would be something on the lines of:
@c1 = 'asdf';
@c2 = NULL;
@c3 = NULL;
@c4 = NULL;
@c5 = NULL;
SQL comes out to:
SELECT *
FROM t
WHERE c1 = COALESCE(@c1, c1)
AND c2 = COALESCE(@c2, c2)
AND c3 = COALESCE(@c3, c3)
AND c4 = COALESCE(@c4, c4)
AND c5 = COALESCE(@c5, c5)
;
Does anyone have an opinion on what method to implement? I'm leaning towards COALESCE, but I have no hard numbers or experience on the matter. Maybe there is a better way of doing things?
sys.columnsview.