TSQL - оператор If..Else внутри табличных функций - не может пройти - PullRequest
16 голосов
/ 05 апреля 2011

Перед публикацией я прочитал несколько статей о разработке функций USD, но не нашел решения для моей проблемы ... что выглядит следующим образом:

У меня очень простая база данных, которая хранит баскетболистов и состоит из столбца ID, возраста, роста и имени. Я хотел бы реализовать функцию 'height' с одним параметром @set varchar (10), которая в зависимости от одного значения @set будет запускать различные операторы выбора

то, что я пытался реализовать, было в псевдо-коде:

CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS TABLE
AS
BEGIN

    IF  (@set = 'tall')
         SELECT * from player where height > 180

    ELSE IF (@set = 'average')
         SELECT * from player where height >= 155 and height <=175

    ELSE IF (@set = 'low')
         SELECT * from player where height < 155
END

Может ли кто-нибудь дать мне подсказку, как это реализовать?

Ответы [ 7 ]

20 голосов
/ 05 апреля 2011

Самая простая форма - всегда лучшая

CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS TABLE
AS RETURN
SELECT * from player
where ((@set = 'tall' and height > 180)
   or (@set = 'average' AND height >= 155 and height <=175)
   or (@set = 'low' AND height < 155))
GO

Эта форма называется табличной функцией INLINE, что означает, что SQL Server может свободно расширять ее, чтобы присоединить проигрыватель непосредственно к другим таблицам в строке большего запроса., заставляя его выполнять бесконечно 1 лучше , чем табличная функция с несколькими утверждениями.

Вы можете предпочесть это, хотя, чтобы ваши диапазоны были полными (у вас естьпромежуток между 175 и 180)

where ((@set = 'tall' and height > 180)
   or (@set = 'average' AND height >= 155 and height <= 180)
   or (@set = 'low' AND height < 155))

SQL Server обеспечивает короткое замыкание ветвей при разборе переменной @set.

1 преувеличение, но незначительно

16 голосов
/ 05 апреля 2011

Вы были близки. Для использования табличной функции с несколькими операторами требуется, чтобы возвращаемая таблица была указана и заполнена в функции:

CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS @Players TABLE
(
    -- Put the players table definition here
) 
AS
BEGIN

    IF  (@set = 'tall')
         INSERT INTO @Players SELECT * from player where height > 180

    ELSE IF (@set = 'average')
         INSERT INTO @Players SELECT * from player where height >= 155 and height <=175

    ELSE IF (@set = 'low')
         INSERT INTO @Players SELECT * from player where height < 155

    RETURN -- @Players (variable only required for Scalar functions)

END

Я бы рекомендовал использовать встроенный TVF, как показывает ответ Ричарда. Это может сделать вывод о возврате таблицы из вашего утверждения.

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

10 голосов
/ 05 апреля 2011

Почему вы жестко программируете это, создайте таблицу высот, а затем захватите все высоты, допустимые для диапазона

SELECT * from player p
join Heights h on p.height between h.heightStart and h.heightEnd 
WHERE h.height  = @set
3 голосов
/ 05 апреля 2011

Это должно сработать.

SELECT * FROM player 
WHERE
  height > CASE 
            WHEN @set = 'tall' THEN 180
            WHEN @set = 'average' THEN 154
            WHEN @set = 'low' THEN 0
          END

Я оставлю <дело для вашего удовольствия. </p>

2 голосов
/ 05 апреля 2011

Примерно так:

CREATE FUNCTION [dbo].[Age](@set VARCHAR(10))  
RETURNS @Players TABLE
(
    playerId INT,
    Name VARCHAR(50)
) 
AS  
BEGIN 

    INSERT INTO @Players
    SELECT playerId, Name
    FROM player 
    WHERE CASE WHEN @set = 'tall' AND height > 180 THEN 1
    WHEN @set = 'average' AND height BETWEEN 155 AND 180 THEN 1
    WHEN @set = 'low' AND height < 155 THEN 1 ELSE 0 END = 1

    RETURN
END
1 голос
/ 24 апреля 2013

Мы можем использовать табличную функцию следующим образом с условиями IF на ней.

CREATE function [dbo].[AA] 
(
@abc varchar(10)
)
Returns  @mytable table
(
supname nvarchar(10), [add] nvarchar(10)
)
AS
begin
-- lOAD WHATEVER THINGS YOU REQUIRED INTO THIS DYNAMIC TABLE
if (@abc ='hh')
    insert into @mytable (supname, [add]) values ('hh','gg'+ @abc)
else
    insert into @mytable (supname, [add]) values ('else','gg'+ @abc)
return
end

--select * from [dbo].[AA]('SDAASF')
0 голосов
/ 27 октября 2015

Согласно Ицик Бен-Гану в своей книге «Запросы TSQL» (Ицик Бен-Ган и др. , (c) 2015, Microsoft Press, ISBN 978-0-7356-8504-8, P. 215) "... Я считаю, что встроенные TVF - это отличный инструмент, позволяющий инкапсулировать логику и возможность повторного использования без каких-либо проблем с производительностью UDF ... "

Он также говорит, что если вам нужно " ... многоразовое табличное выражение, такое как View, но вам также нужно передать входные параметры в табличное выражение ... TSQL предоставляет встроенные функции с табличными значениями (TVF) ."

Этот тип 'IF' ( встроенная функция - отдельный тип в sys.objects ) использует выходной спецификатор 'RETURNS TABLE' и, по-видимому, не может содержать BEGIN / END. Синтаксис и допуски очень ограничены, но мы видим хорошую оптимизацию и производительность. На эти факторы указывает время, увиденное @ ryk.

...