I am implementing a searching mechanism in a website and stumbled upon the SQL aspect of it.
The user can search for stories by any combination of these filters: story title, story tag, or the username of the story’s author. If no filter is provided, then just return all stories.
My immediate solution to this is this stored procedure:
(
@TitleFilter varchar(50) = NULL
,@TagFilter varchar(30) = NULL
,@UserFilter varchar(30) = NULL
)
SELECT
story.Title
,story.AddedDTS
FROM
Stories story
INNER JOIN FREETEXTTABLE(Stories, Title, @TitleFilter) ft
ON ft.[key] = story.ID
LEFT JOIN StoryTags st
ON st.StoryID = story.ID
LEFT JOIN Tags tag
ON tag.ID = st.TagID
LEFT JOIN StoryUser su
ON su.StoryID = story.ID
LEFT JOIN Users u
ON u.ID = su.UserID
WHERE
1=1
AND (
(@TagFilter IS NULL AND @UserFilter IS NULL)
OR (@TagFilter IS NOT NULL AND tag.Name = @TagFilter)
OR (@UserFilter IS NOT NULL AND u.Username = @UserFilter)
)
There’s a couple of problems with this, though, and I am yet to find a better approach.
First off, the Stories table has full-text search enabled, so I have to use the FREETEXTTABLE mechanism, which mandates the predicate to not be NULL, so this stored procedure will not work with @TitleFilter set to NULL.
Secondly, if I only search by title, then joining to StoryTags, Tags, StoryUsers, and Users tables are merely a useless overhead.
So the question is for both points I stated: can I conditionally omit joins to optimize the execution time?
If there’s a whole different approach to this, you are more than welcome to share it; I advocate thinking out of the box.
Given that when @TitleFilter is null it doesn’t work with FREETEXTTABLE I would either break it up with an if statement like so.
Or if that offends you for some reason there’s always The Curse and Blessings of Dynamic SQL