Как сделать единичное условие для этого SQL-запроса? - PullRequest
2 голосов
/ 27 февраля 2009

Я использую MSSQL 2005 Server, и у меня есть следующий запрос SQL.

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

В приведенном выше запросе у меня есть условие категории,

d.CategoryId=@CategoryId

, который выполняется, когда передается любая категория, если категория не пропущена, то я не рассматриваю условие категории в предложении where, Для реализации условия категории только тогда, когда если в категории (1,2,3) я использовал Клаус, но мы не можем сделать это в одиночном, где запрос ?? это означает, что просто проверьте, есть ли значения в категории (или если это просто, тогда мы можем проверить только 1,2,3 значения), тогда это условие будет применено, иначе запрос не будет учитывать условие категории.

Есть ли способ использовать операторы CASE или NOT NULL ??

Ответы [ 6 ]

2 голосов
/ 27 февраля 2009

Если единственное различие заключается в предложении where, то вы можете сделать это:

d.CategoryId = COALESCE(@CategoryId, d.CategoryId)

Не уверен, зачем вам нужен оператор IN (IN (1,2,3)), поскольку вы упомянули, что ваша причина для проверки состоит в том, чтобы убедиться, что он не равен NULL. Так что это должно работать так, как вы описали.

2 голосов
/ 27 февраля 2009

Если @CategoryId равен NULL, если вы не хотите фильтровать по нему, вы можете использовать следующее условие ...

ISNULL(@CategoryId, d.CategoryId) = d.CategoryId

Так что, если он равен NULL, он равен себе и не фильтрует

EDIT

Мне нравится пример COALESCE Марка Миллера, и вы можете использовать любой из них, и я действительно не должен комментировать исполнение одного стиха другим, но ...

Моя интуиция говорит мне, что ISNULL должен победить, но посмотрит на некоторые споры по этому вопросу, если вам нечего делать (или если производительность действительно критична в этом запросе).

ПРИМЕЧАНИЕ: Если d.CategoryId в таблице может быть ПУСТО (NULL), тогда этот подход потерпит неудачу, и следует использовать СЛУЧАЙ, КОГДА ТОГДА в другом месте по этому вопросу

1 голос
/ 27 февраля 2009

По оценкам ответа вы можете сделать следующее:

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_Data

Таким образом вы устраняете вызов функции

1 голос
/ 27 февраля 2009

Может ли быть ЛЕВОЕ СОЕДИНЕНИЕ там, как это:

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_Data

вам больше не понадобится оператор if.

Кроме того, очень важно, чтобы у вас был c.CategoryId=@CategoryId в левом соединении, если вы переместите его в предложение WHERE, оно заставит левое соединение во внутреннее соединение.

1 голос
/ 27 февраля 2009

Если категория в 1,2 или 3, тогда используйте указанный @CategoryId для фильтрации или не проверяйте себя.

AND IsNull(d.CategoryId, 1) = case when @CategoryId in (1,2,3) then @CategoryId else IsNull(d.CategoryId, 1) end

Этот запрос также работает , когда @ Category или CategoryId равен нулю И утверждение «если» может исчезнуть.

Полный запрос ниже

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

* ПРЕДУПРЕЖДЕНИЕ : Убедитесь, что по плану выполнения проверяется, медленнее ли приведенный выше запрос, чем использование оператора "if".

1 голос
/ 27 февраля 2009

Выполнение ((@CategoryId IN (1,2,3) AND CategoryId = @ CategoryId) ИЛИ НЕ @CategoryId IN (1,2,3)) проверит идентификатор категории, если оно равно 1, 2 или 3, в противном случае оно не будет применять этот фильтр.

    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
...