TSQL - If..Else statement внутри Table-Valued Functions - не может пройти
Перед публикацией я прочитал несколько статей о разработке функций USD, но не нашел решения для своей проблемы... что выглядит следующим образом:
У меня очень простая база данных, в которой хранятся баскетболисты и состоит из столбца ID, Age, Height и Name. То, что я хотел бы сделать, это реализовать функцию 'height' с одним параметром @set varchar (10), что в зависимости от одного значения @set будут вызывать разные команды выбора
то, что я пытался реализовать, было в psuedo-code:
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
Может ли кто-нибудь дать мне подсказку, как его реализовать?
Ответы
Ответ 1
Простейшая форма всегда лучшая
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 преувеличение, но только слегка
Ответ 2
Почему вы это жестко кодируете, создаете таблицу высот и затем захватываете все высоты, которые действительны для диапазона
SELECT * from player p
join Heights h on p.height between h.heightStart and h.heightEnd
WHERE h.height = @set
Ответ 3
Ты был близок. Использование многозадачной табличной функции требует, чтобы таблица возврата была указана и заполнена в функции:
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 является менее черным ящиком для оптимизатора и больше похож на параметризованный вид с точки зрения оптимизации, способного переупорядочивать вещи с помощью других таблиц и представлений в одном и том же плане выполнения.
Ответ 4
Это должно работать.
SELECT * FROM player
WHERE
height > CASE
WHEN @set = 'tall' THEN 180
WHEN @set = 'average' THEN 154
WHEN @set = 'low' THEN 0
END
Я оставлю < дело для вашего удовольствия.
Ответ 5
Что-то вроде этого:
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
Ответ 6
Мы можем использовать функцию табличных значений следующим образом с условиями 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')
Ответ 7
По словам Ицика Бен-Гана в его книге "TSQL Querying" (Itzik Ben-Gan et al, (c) 2015 Microsoft Press, ISBN 978-0-7356-8504-8, стр. 215) "... Я считаю встроенные ТВФ отличным инструментом, позволяющим инкапсулировать логику и повторное использование без каких-либо проблем с производительностью UDF..."
Он также говорит, что если вам нужно "... многоразовое табличное выражение типа View, но вам также нужно передать входные параметры в выражение таблицы... TSQL предоставляет встроенные функции, основанные на таблицах (TVF)".
Этот тип "IF" (встроенная функция - отдельный тип в sys.objects) использует спецификатор вывода RETURNS TABLE и, по-видимому, не может содержать BEGIN/END. Синтаксис и допуски очень ограничительны, но мы видим хорошую оптимизацию и производительность. Эти факторы указаны таймингами, наблюдаемыми @ryk.