Я хочу записать хранимую процедуру, которая работает что-то вроде этого:
SELECT * from T where T.A = @a and T.B = @b
если это возвращает строки, возвратите те строки, в противном случае возвратитесь
SELECT * from T where T.A = @a and T.B IS NULL
Править:
Это чувствует, что должен быть способ создать процедуру, таким образом, что это выполняет первый запрос однажды и выполняет второй запрос только если необходимый.
Редактирование конца.
Лучшим, которым я мог управлять, было следование, которое (в теории) выполняет первый запрос дважды, если, возможно, его кэшируемый:
IF EXISTS (SELECT * from T where T.A = @a and T.B = @b) THEN
SELECT * from T where T.A = @a and T.B = @b
ELSE
SELECT * from T where T.A = @a and T.B IS NULL
Поскольку, что его ценность, это находится в Microsoft SQL Server 2008
Это должно исключить дополнительный доступ к таблице для проверки существования. Я не уверен, что есть способ лучше.
SELECT * from T where T.A = @a and T.B = @b
IF (@@ROWCOUNT = 0)
BEGIN
SELECT * from T where T.A = @a and T.B IS NULL
END
Я думаю, вы можете сделать это с помощью табличной переменной, что позволит избежать проблемы с двумя наборами результатов. Что-то вроде:
declare @result1 table ( ... )
insert into @result1 select * from T where T.A = @a and T.B = @b
if (@@rowcount = 0)
select * from T where T.A = @a and T.B is null
else
select * from @result1
Почему вы не можете сделать это в одном запросе:
Select ...
From T
Where T.A = @a
And T.B = @b
Union All
Select ...
From T
Where T.A = @a
And T.B Is Null
And Not Exists (
Select 1
From T
Where T.A = @a
And T.B = @b
)
Другое решение для отдельного запроса:
Select ...
From T
Where T.A = @a
And T.B = @b
Union All
(Select ...
From T
Where T.A = @a
And T.B Is Null
Except
Select ...
From T
Where T.A = @a
And T.B = @b)
Вы также можете сделать это с помощью одного запроса:
SELECT * from T where (T.A = @a and T.B = @b) OR
( 0=(SELECT COUNT(*) T1 where (T1.A = @a and T1.B = @b) )
AND T.A = @a and T.b IS NULL)
Я не знаю, помогает ли это вообще с точки зрения производительности, но вы можете попробовать функцию с табличным значением:
create function fun(@a <aType>, @b <bType>)
returns @result (<...columns...>)
as begin
insert into @result
select * from T where T.A = @a and T.B = @b;
if (@@ROWCOUNT = 0) begin
insert into @result
select * from T where T.A = @a and T.B is null;
end;
return;
end;
GO
Но я сомневаюсь, что это поможет.
В целом я придерживаюсь вашего оригинального подхода. Он самый простой и чистый. А кеш и хороший индекс должны позаботиться о производительности.
Если бы здесь были реальные проблемы с производительностью, я бы отступил и посмотрел на этот дизайн базы данных. Почему у вас там нули? Почему вы пробуете два фильтра? Можно по-другому смоделировать? Если нет, может быть, небольшая денормализация?
EDIT Ответ был отредактировано после того, как вопрос был отредактирован.
CREATE PROCEDURE myconditionalsp
@a <type>,
@b <type>
AS
SELECT * from T
where
-- the second condition is true AND the first condition is false
(((T.A = @a) and (T.B IS NULL)) AND NOT ((T.A = @a) and (T.B = @b)))
OR
-- the first condition is true (regardless what is the second condition)
((T.A = @a) and (T.B = @b))
GO