2010-06-24 2 views
1

Мне нужна помощь в разрешении сложного SQL-запроса. Я пытаюсь создать запрос один vlock за раз. Одна проблема:: Если параметр для @PubNum равен NULL, запрос показывает «..... где PubNum =», что является проблемой. Что мне нужно, если параметр NULL, тогда PubNum не должен быть . в пункте гдеСложный динамический SQL-запрос

Второй вопрос:

  • Если @StartDate НЕ NULL и @EndDate IS NOT NULL THEN RecAddDate МЕЖДУ @StartDate и @EndDate
  • Если @StartDate НЕ NULL и @EndDate IS NULL THEN RecAddDate BETWEEN @StartDate И сегодня
  • Если @StartDate IS NULL и @EndDate IS NOT NULL THEN RecAddDate МЕЖДУ '01/01/2000' И @EndDate
  • Если @StartDate IS NULL и @EndDate IS NULL THEN RecAddDate МЕЖДУ '01/01/2000' AND Сегодня

Любые идеи?

Полный запрос:

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) 
+0

Хммм, это в основном то, что вы уже делаете. Вы уверены, что не получаете '' (пустую строку) для @PubNum, а не NULL?Другим намеком на это является тот факт, что базовая конкатенация строк, например «select» a + NULL, полностью возвращает NULL (я думаю, по умолчанию, вы можете изменить это поведение), поэтому в вашем случае я действительно думаю, что вы получаете ' для @PubNum, где вы ожидаете NULL. – Rob

+0

Правильно, я получаю пустую строку. Я хочу, чтобы PubNum НЕ SHOW в предложении where, если переданное значение равно null. – user279521

+0

Разве это не две разные вещи, которые вы описываете? Ваш тест рассчитан на значения NULL, которые должны работать нормально. Но вы получаете пустую строку, которая не является NULL, поэтому она проходит этот тест и дает вам нежелательный результат. Добавьте тест, например, IF @PubNum IS NOT NULL AND @PubNum <> '', возможно, это ваше решение. – Rob

ответ

4

Вместо того чтобы делать динамический SQL (который вводит целый ряд проблем, и часто это на самом деле не нужно), вы могли бы просто использовать параметры и некоторые NULL проверки, как часть вашего WHERE с использованием нескольких различных методов, в зависимости от того, что вы пытаетесь сделать. Я тестировал это с помощью SQL 2000/2005, и он работает правильно (я бы тоже предположил, что это нормально в 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 
+0

Я все еще пытаюсь это сделать, но любопытно узнать ... если я использую проверку ISNULL, не будет ли отображаться PubNum в том месте, если значение равно null? – user279521

+0

Не работает. Я получаю ISNULL (@PubNum, PubNum) = PubNum в предложении where вместо значения для @PubNum – user279521

+0

@ user279521: похоже, что вы все еще можете использовать динамический SQL для запуска этого запроса - вам не нужно к. Я расширил образец кода, чтобы сделать это понятным. В случае, когда @PubNum имеет значение NULL, он сравнивает столбец PubNum с самим собой, что будет истинно - эффективно, что приводит к тому, что он не будет отфильтрован этим столбцом - как и исходный запрос, - но если @PubNum был установлен пользователь, то он будет фильтровать это вместо этого. – SqlRyan

1

Я бы условно включать фильтры, если не было нулевым. Что-то вроде этого: -

Set @WhereClause = 'Where 1=1' 
If @PubNum is not null 
    Set @WhereClause = @WhereClause + ' AND PubNum = ''' + @PubNum + '''' 
0

Для вашего второго вопроса:

(@StartDate не отображает значение параметра, а не отображает "..... StartDate = @StartDate .....")

Если вы хотите продолжать использовать динамический SQL, рассмотрите возможность замены EXECUTE на sp_executesql. Эта хранимая процедура будет принимать параметры, которые затем можно использовать внутри динамического SQL (замена параметров). Например:

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

Для выше, добавьте @EndDate_PARAM в качестве параметра, как так:

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

Это выглядит немного странно на первый, но это хорошая вещь, чтобы сделать, если вы идете по динамическому пути SQL.

Вы найдете более подробную информацию о том, что здесь: http://msdn.microsoft.com/en-us/library/ms175170.aspx

Смежные вопросы