Хранимая процедура с условными результатами - PullRequest
5 голосов
/ 02 июля 2010

Я хочу написать хранимую процедуру, которая работает примерно так:

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

Ответы [ 7 ]

5 голосов
/ 02 июля 2010

Это должно исключить дополнительный доступ к таблице для проверки существования.Я не уверен, есть ли более аккуратный способ.

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
1 голос
/ 02 июля 2010

Я думаю, что вы можете сделать это с помощью табличной переменной, которая должна избежать проблемы с двумя наборами результатов.Что-то вроде:

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
0 голосов
/ 26 октября 2018

Попробуйте, если первый выбор возвращает строки, затем возвращается, если первый не удастся, затем возвращается следующий выбор или, наконец, последний выбор:

IF EXISTS(SELECT * FROM Customers 

     INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID where Customers.CustomerID='BERJGS')
    BEGIN
             SELECT * FROM Customers 
                    INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID where Customers.CustomerID='BERJGS'
              PRINT 'TOLA'
              RETURN
     END
ELSE
     BEGIN
               SELECT * FROM Customers 
                    INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID where Customers.CustomerID='6CHOPS'             
              IF @@ROWCOUNT > 0             
                    RETURN              
              --RETURN
     END



SELECT * FROM Customers  where Customers.CustomerID='FRANK'
0 голосов
/ 02 июля 2010

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

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

Но я сомневаюсь, что это помогает.

Как правило, я быпридерживаться вашего оригинального подхода.Это самый простой и чистый.А кэш и хороший индекс должны заботиться о производительности.

Если бы здесь были реальные проблемы с производительностью, я бы отступил назад и взглянул бы на этот дизайн базы данных.Почему у вас там нули?Почему вы пробуете два фильтра?Можно ли смоделировать по-другому?Если нет, может быть, немного денормализации?

0 голосов
/ 02 июля 2010

Почему вы не можете сделать это в одном запросе:

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)
0 голосов
/ 02 июля 2010

Вы также можете сделать это одним запросом:

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)
0 голосов
/ 02 июля 2010

РЕДАКТИРОВАТЬ Ответ был отредактирован после редактирования вопроса.

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