Обойти последнее ВНУТРЕННЕЕ СОЕДИНЕНИЕ в запросе - PullRequest
1 голос
/ 30 сентября 2010

У меня есть следующая хранимая процедура, которая принимает идентификатор пользователя, дату начала, дату окончания и список кодов в списке, разделенном запятыми, и возвращает все записи активности между этими двумя датами, которые соответствуют одной из коды в списке.

ALTER PROCEDURE [dbo].[ActivitiesSummary] 

@UserID varchar(30),
@StartDate datetime,
@EndDate datetime,
@Codes varchar(100)

AS

BEGIN

 SET NOCOUNT ON;

 SELECT act.SectionID, act.UnitID, act.ActivityCode
 FROM dbo.Activities act INNER JOIN ConvertCodeListToTbl(@Codes) i ON act.ActivityCode = i.code
 WHERE act.ActivityDate>=@Startdate AND act.ActivityDate<@EndDate
 GROUP BY act.SectionID, act.UnitID, act.ActivityCode
 ORDER BY act.SectionID, act.UnitID, act.ActivityCode
END

ConvertCodeListToTbl (@Codes) - это функция, которая принимает список кодов, разделенных запятыми (например, «A0001, B0001, C0001») и возвращает таблицу с одним кодом на строку:

A0001
B0001
C0001

Этот метод работает очень хорошо, за исключением случаев, когда коды не были выбраны. Когда это происходит, я не получаю никаких записей назад, потому что @ Codes = '' и последнее INNER JOIN не возвращает никаких записей.

То, что я хочу, чтобы произошло: если @ Codes = '', игнорировать последнее INNER JOIN или иным образом найти способ вернуть все записи независимо от кода.

Какие у меня варианты?

Ответы [ 5 ]

1 голос
/ 30 сентября 2010

Звучит так, будто вам нужно изменить строку INNER JOIN на:

FROM dbo.Activities act INNER JOIN ConvertCodeListToTbl(@Codes) i 
ON (act.ActivityCode = i.code OR @Codes = '')
0 голосов
/ 30 сентября 2010

Я не знаю, как будет сравниваться производительность, но это должен быть другой идентичный запрос, который делает то, что вы хотите:

SELECT act.SectionID, act.UnitID, act.ActivityCode 
FROM dbo.Activities act
WHERE act.ActivityDate>=@Startdate AND act.ActivityDate<@EndDate
    AND (@Codes = '' OR
         EXISTS
           (SELECT *
            FROM ConvertCodeListToTbl(@Codes)
            WHERE act.ActivityCode = code))
GROUP BY act.SectionID, act.UnitID, act.ActivityCode 
ORDER BY act.SectionID, act.UnitID, act.ActivityCode

Другой вариант - это ConvertCodeListToTbl return SELECT ActivityCode FROM dbo.Activities когдаего вход пуст.

0 голосов
/ 30 сентября 2010

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

... i ON (act.ActivityCode = i.code) OR IF(@codes = '', 1, 0)

по существу объединит везде, если @codes пуст.

0 голосов
/ 30 сентября 2010

На сервере SQL вы можете установить значение по умолчанию для параметра в хранимой процедуре.

Измените строку вверху на:

@Codes varchar(100) = '*'

Затем ваш другой процесс ConvertCodeListToTbl возвращает все значения, если ему передано '*' в качестве параметра.

0 голосов
/ 30 сентября 2010

Я не уверен в способе сделать это в SQL, который бы не испортил план запроса (например, вы могли бы сделать это с помощью динамического sql, но тогда бы вы производили два совершенно разных запроса).

Ваше вызывающее приложение должно знать, что @codes пусто, прежде чем оно вызовет хранимую процедуру, так почему бы не вызвать другую хранимую процедуру, которая не выполняет соединение?

...