I am using MSSQL 2005 Server and I have the following SQL query.
IF @CategoryId IN (1,2,3)
BEGIN
INSERT INTO @search_temp_table
SELECT * FROM (SELECT d.DataId, (SELECT [Name] FROM Category WHERE CategoryId = d.CategoryId) AS 'Category', d.Description, d.CompanyName, d.City, d.CategoryId,
d.CreatedOn, d.Rank, d.voteCount, d.commentCount, d.viewCount
FROM Data d
INNER JOIN Keyword k
ON d.DataId = k.DataId
WHERE FREETEXT(k.Keyword, @SearchQ) AND d.CategoryId=@CategoryId AND d.IsSearch=1 AND d.IsApproved=1 ) AS Search_Data
END
ELSE
BEGIN
INSERT INTO @search_temp_table
SELECT * FROM (SELECT d.DataId, (SELECT [Name] FROM Category WHERE CategoryId = d.CategoryId) AS 'Category', d.Description, d.CompanyName, d.City, d.CategoryId,
d.CreatedOn, d.Rank, d.voteCount, d.commentCount, d.viewCount
FROM Data d
INNER JOIN Keyword k
ON d.DataId = k.DataId
WHERE FREETEXT(k.Keyword, @SearchQ) AND d.IsSearch=1 AND d.IsApproved=1 ) AS Search_Data
END
In the above query I have the category condition,
d.CategoryId=@CategoryId
which is executed when any category is passed, if no category is passed then I am not considering category condition in where clause, To implement category condition only when if the category in (1,2,3) I have used If-Clause, but can't we do this in single where query?? that means just check if the values is there in the category (or if it's easy then we can only check for 1,2,3 values) then that condition will be applied else query will not consider the category condition.
Is there any way, using CASE, or NOT NULL statements ??
-
If @CategoryId is NULL when you don't want to filter by it you can use the below condition...
ISNULL(@CategoryId, d.CategoryId) = d.CategoryIdSo if it's NULL then it equals itself and wont filter
EDIT
I like Marc Miller's COALESCE example and you could use either and I really shouldn't comment on the performance of one verses the other but...
My gut tells me ISNULL should win out but have a look at some of the debates on this issue if you have nothing better to do (or if performance is REALLY critical in this query).
NOTE: If the d.CategoryId in the table can be NULL then this approach will fail and the CASE WHEN THEN approach elsewhere on this question should be used
Sung Meister : This doesn't check whether @Category is in 1,2 or 3.Rich Andrews : Hmm - they way I read the question was that the values passed in could only be 1,2 or 3 and that was why they were in the IF statement. Either way it's a bloody good way of implementing optional filtering :)Tom H. : This may also fail if the CategoryId in the table can be NULLRich Andrews : Good point - I've generally used this approach on IDENTITY columns so it's not been a problem for me in the past but I'll edit the post to point this out. -
Doing a ((@CategoryId IN (1,2,3) AND CategoryId=@CategoryId) OR NOT @CategoryId IN (1,2,3)) will check category id if it is 1, 2 or 3 otherwise it won't apply that filter.
WHERE FREETEXT(k.Keyword, @SearchQ) AND ((@CategoryId IN (1,2,3) AND d.CategoryId=@CategoryId) OR NOT @CategoryId IN (1,2,3)) AND d.IsSearch=1 AND d.IsApproved=1 ) AS Search_Data -
If category is in 1,2 or 3 then use the specified @CategoryId to filter or else don't by checking itself.
AND IsNull(d.CategoryId, 1) = case when @CategoryId in (1,2,3) then @CategoryId else IsNull(d.CategoryId, 1) endThis query also works when @Category or CategoryId is null And the "If" statement can go away.
Full query below
INSERT INTO @search_temp_table SELECT * FROM (SELECT d.DataId, (SELECT [Name] FROM Category WHERE CategoryId = d.CategoryId) AS 'Category', d.Description, d.CompanyName, d.City, d.CategoryId, d.CreatedOn, d.Rank, d.voteCount, d.commentCount, d.viewCount FROM Data d INNER JOIN Keyword k ON d.DataId = k.DataId WHERE FREETEXT(k.Keyword, @SearchQ) AND IsNull(d.CategoryId, 1) = case when @CategoryId in (1,2,3) then @CategoryId else IsNull(d.CategoryId, 1) end AND d.IsSearch=1 AND d.IsApproved=1 ) AS Search_Data*WARNING: Make sure to check against execution plan whether above query is slower than using "if" statement.
Tom H. : This may not return the correct data if the CategoryId in the table can be NULLSung Meister : It should work now even though CategoryId is null -
If the only difference is your where clause then you could do this:
d.CategoryId = COALESCE(@CategoryId, d.CategoryId)Not sure why you need the IN clause (IN (1,2,3)) as you mentioned that your reason for checking for it is to make sure it isn't NULL. So this should work the way you described.
-
Could do a LEFT JOIN in there, like this:
INSERT INTO @search_temp_table SELECT * FROM ( SELECT d.DataId, c.[Name] as 'Category', d.Description, d.CompanyName, d.City, d.CategoryId, d.CreatedOn, d.Rank, d.voteCount, d.commentCount, d.viewCount FROM Data d INNER JOIN Keyword k ON d.DataId = k.DataId LEFT JOIN Category c on c.CategoryId=d.CategoryId AND c.CategoryId=@CategoryId WHERE FREETEXT(k.Keyword, @SearchQ) AND d.IsSearch=1 AND d.IsApproved=1 ) AS Search_Datayou wouldn't need the if statement anymore either.
Also, it's very important that you have the c.CategoryId=@CategoryId within the LEFT JOIN, if you move it to the WHERE clause it will force the LEFT JOIN into an INNER JOIN.
-
Similiar to marks answer you can do the following:
WHERE FREETEXT(k.Keyword, @SearchQ) AND d.IsSearch=1 AND d.IsApproved=1 AND ((@CategoryId NOT IN (1,2,3)) OR (d.CategoryId = @CategoryId)) ) AS Search_DataThis way you eliminiate the function call
0 comments:
Post a Comment