views:

92

answers:

3

I need help in resolving a complex SQL query. I am trying to build up the query one vlock at a time. One issue is: If a parameter for @PubNum is NULL, the query shows "..... where PubNum = '' which is an issue. What I need is if the parameter is NULL, then PubNum should not be in the where clause.

A second issue is:

  • If @StartDate IS NOT NULL and @EndDate IS NOT NULL THEN RecAddDate BETWEEN @StartDate AND @EndDate
  • If @StartDate IS NOT NULL and @EndDate IS NULL THEN RecAddDate BETWEEN @StartDate AND Today
  • If @StartDate IS NULL and @EndDate IS NOT NULL THEN RecAddDate BETWEEN '01/01/2000' AND @EndDate
  • If @StartDate IS NULL and @EndDate IS NULL THEN RecAddDate BETWEEN '01/01/2000' AND Today

Any ideas?

The complete query is:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[usp_BookItemSearch]
    @BookSKU varchar(30) = NULL
    ,@SearchType int = NULL
    ,@PubNum varchar(10) = NULL
    ,@UserID int = NULL
    ,@StartDate smalldatetime = NULL
    ,@EndDate smalldatetime = NULL
AS
DECLARE @SQL as varchar(4000)

SET @SQL = 'SELECT RecID, PubNum, VendorName, InvoiceNum, BookSKU, RecAddDate FROM tb_BookInventoryLog]'

IF @BookSKU IS NOT NULL
    BEGIN
        IF  @SearchType = 2
            BEGIN
                SET @SQLClause = ' WHERE BookSKU LIKE ''%' + @BookSKU + ''''    --Ends with
            END
        IF  @SearchType = 1
            BEGIN
                SET @SQLClause = ' WHERE BookSKU LIKE ''%' + @BookSKU + '%'''   --Contains
            END
        IF  @SearchType = 0
            BEGIN
                SET @SQLClause = ' WHERE BookSKU LIKE ''' + @BookSKU + '%'''    --Starts with
            END
    END

IF @PubNum IS NOT NULL
    BEGIN
        IF @SQLClause IS NOT NULL
            BEGIN
                SET @SQLClause = @SQLClause + ' AND PubNum = ''' + @PubNum + ''''
            END
        ELSE
            BEGIN
                SET @SQLClause = @SQLClause + ' WHERE PubNum = ''' + @PubNum + ''''
            END
    END

IF @UserID IS NOT NULL 
    BEGIN
        IF @SQLClause IS NOT NULL
            BEGIN
                SET @SQLClause = @SQLClause + ' AND (UserID = ' + CAST(@UserID AS VarChar) + ')'
            END
        ELSE
            BEGIN
                SET @SQLClause = @SQLClause + ' WHERE (UserID = ' + CAST(@UserID AS VarChar) + ')'
            END
    END

If (@StartDate Is Not Null) AND (@EndDate Is Not Null)
    BEGIN
            Set @SQLClause = @SQLClause + ' And (JoiningDate BETWEEN @StartDate AND @EndDate)'
    END

IF (@EndDate IS NOT NULL)
    BEGIN
        IF (@StartDate IS NOT NULL) 
            BEGIN
                SET @SQL = @SQL +  ' WHERE RecAddDate between' + CAST(@StartDate As smalldatetime) + ' AND ' + CAST(@EndDate as smalldatetime) + ''
            END
        ELSE
            BEGIN
                SET @SQL = @SQL +  ' RecAddDate BETWEEN 01/01/2000 AND @EndDate + '
            END
    END

SET @SQL = @SQL + @SQLClause + ' ORDER BY BookSKU, PubNum'
PRINT @SQL
--EXECUTE (@SQL)
+1  A: 

I would conditionally include the filters if there were not null. Something like this:-

Set @WhereClause = 'Where 1=1'
If @PubNum is not null
  Set @WhereClause = @WhereClause + ' AND PubNum = ''' + @PubNum + ''''
SPE109
+4  A: 

Instead of doing dynamic SQL (which introduces a whole number of problems, and often isn't actually necessary), you could just use the parameters and some NULL checks as part of your WHERE clause using a couple of different techniques, depending on what you're trying to do. I tested this using SQL 2000/2005, and it works correctly (I'd also assume it's fine in 2008/R2).

ALTER PROCEDURE [dbo].[usp_BookItemSearch]
    @BookSKU varchar(30) = NULL
    ,@SearchType int = NULL
    ,@PubNum varchar(10) = NULL
    ,@UserID int = NULL
    ,@StartDate smalldatetime = NULL
    ,@EndDate smalldatetime = NULL
AS


  SELECT RecID, PubNum, VendorName, InvoiceNum, BookSKU, RecAddDate
    FROM [tb_BookInventoryLog]
   WHERE (
          (@BookSKU IS NULL) OR 
          (BookSKU LIKE CASE @SearchType
                          WHEN 0 THEN       @BookSKU + '%'
                          WHEN 1 THEN '%' + @BookSKU + '%'
                          WHEN 2 THEN '%' + @BookSKU
                        END
          )
         )
     AND ISNULL(@PubNum, PubNum) = PubNum
     AND ISNULL(CAST(@UserID AS VARCHAR), UserID) = UserID
     AND (
          (@StartDate IS NULL OR @EndDate IS NULL) OR
          (JoiningDate BETWEEN @StartDate AND @EndDate)
         )
     AND RecAddDate BETWEEN CASE
                              WHEN @EndDate IS NULL THEN RecAddDate
                              ELSE ISNULL(@StartDate, '01/01/2000')
                            END
                        AND ISNULL(@EndDate, GETDATE())
ORDER BY BookSKU, PubNum
rwmnau
I am still trying this out, but curious to know... if I use the ISNULL check, would that not display PubNum in the where clasue if the value is null?
user279521
Not working. I am getting ISNULL(@PubNum, PubNum) = PubNum in the where clause, instead of a value for @PubNum
user279521
@user279521: It sounds like you may still be trying to use dynamic SQL to run this query - you don't need to. I've expanded the code sample to make that clear. In the case where @PubNum is null, it will compare the PubNum column to itself, which will be true - effectively, that results in it not being filtered by that column - same as your original query - but if @PubNum has been set by the user, then it will filter by that instead.
rwmnau
Hey @rwmnau , that works. Thanks. Could you please help in the last part of the query... the date range? I have updated my original post to reflect issue # 2;
user279521
@user279521: I haven't syntax-checked that, but hopefully there's no trouble there. Let me know if it accomplishes what you need, or if you're unclear about something I'm doing (or it's not correct, and I'm happy to try and correct it). I believe I've handled your "problem 2" correctly, but let me know if it's not doing what you expect.
rwmnau
@rwmnau, I think the date part is messing up. I put in a @startDate of 01/01/2001 and an @EndDate of 12/31/2002 and I dont get any records. There is a record with a RecAddDate of "26 Mar 2001"
user279521
@user279521: Hmm - it seems that I doesn't like the # symbols that I'm using near the date at the end, so I've removed those. But in any case, I've tested this using those two variable values and a test date value of the string you've provided, and SQL pulls back the row. Is there another reason in the filtering that it might not be getting returned?
rwmnau
I tried it without the # and still isnt working. Just curious, is "JoiningDate" a keyword in SQL? I am in the process of converting a coldfusion app into asp.net, so not sure where I got the "JoiningDate" from.
user279521
@user279521: JoiningData isn't a keyword that I'm aware of it, and a quick Google search doesn't seem to turn anything up. I assumed that was a field on your source table - is that not the case? All that line in the WHERE clause does is ensure that, as long as you've provided both a @StartDate and @EndDate, the JoiningDate field falls between them. If you've not provided one or the other (or both), it will ignore the contents of this field for the filtering.
rwmnau
JoiningData is not a field in my source table.
user279521
@rwmnau, I greatly appreciate your help on this. I ended up resolving the Date issue by checking for NULL on the asp side, and then passing the default values if StartDate / EndDate is null, so the stored proc always gets some valid value; Thanks again.
user279521
A: 

For your second issue:

(@StartDate does not display the value of the parameter, instead displays ".....StartDate = @StartDate.....")

If you wish to keep using the dynamic SQL, consider replacing EXECUTE with sp_executesql. That stored procedure will accept parameters which you can then use inside your dynamic SQL (parameter substitution). For example:

Set @SQLClause = @SQLClause + ' And (JoiningDate BETWEEN @StartDate_PARAM AND @EndDate_PARAM)'

For the above, add @EndDate_PARAM as a parameter like so:

exec sp_executesql @SQL, N'@StartDate_PARAM DateTime, @EndDate_PARAM DateTime', @StartDate_PARAM = @StartDate, @EndDate_PARAM = @EndDate

It looks a little weird at first, but it's a good thing to do if you're going the dynamic SQL route.

You'll find more information on that here: http://msdn.microsoft.com/en-us/library/ms175170.aspx

Rob