表值函数中的TSQL-If..Else语句-无法通过

表值函数中的TSQL-If..Else语句-无法通过,sql,sql-server,database,tsql,user-defined-functions,Sql,Sql Server,Database,Tsql,User Defined Functions,在发帖之前,我读了一些关于开发USD函数的文章,但没有遇到解决我问题的方法。。。详情如下: 我有一个非常简单的数据库,它存储篮球运动员,由ID、年龄、身高和姓名列组成。我想做的是用一个参数@set varchar10实现一个函数“height”,根据一个@set值将触发不同的select语句 我试图实现的是psuedo代码: CREATE FUNCTION [dbo].[age](@set varchar(10)) RETURNS TABLE AS BEGIN IF (@set =

在发帖之前,我读了一些关于开发USD函数的文章,但没有遇到解决我问题的方法。。。详情如下:

我有一个非常简单的数据库,它存储篮球运动员,由ID、年龄、身高和姓名列组成。我想做的是用一个参数@set varchar10实现一个函数“height”,根据一个@set值将触发不同的select语句

我试图实现的是psuedo代码:

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
谁能给我一个如何实现它的提示吗?

这应该行得通

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

我将把<案例留给您欣赏。

为什么要硬编码,创建一个高度表,然后获取该范围内所有有效的高度

SELECT * from player p
join Heights h on p.height between h.heightStart and h.heightEnd 
WHERE h.height  = @set
大概是这样的:

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

最简单的形式总是最好的

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
这种形式称为内联表函数,这意味着SQL Server可以自由扩展它,将player直接连接到更大查询中的其他表,从而使它比多语句表值函数执行得更好

不过你可能更喜欢这个,这样你的范围就完整了,你的差距在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夸张,但只是稍微

你很接近。使用多语句表值函数需要在函数中指定并填充返回表:

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
正如Richard的回答所示,我建议使用内置TVF。它可以从语句中推断表返回


还要注意的是,多语句和内联TVF实际上是完全不同的。内联TVF对于优化器来说不是一个黑匣子,更像是一个参数化视图,因为优化器能够在同一执行计划中与其他表和视图一起重新安排内容。

我们可以按照下面的方式使用表值函数,并在其上设置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

根据Itzik Ben Gan在他的书TSQL查询Itzik Ben Gan等人,c 2015微软出版社,ISBN 978-0-7356-8504-8,第215页中的说法……我发现内联TVFs是一个伟大的工具,允许封装逻辑和可重用性,而不存在UDF的任何性能问题

他还说,如果您需要一个可重用的表表达式(如视图),但您还需要将输入参数传递给表表达式……TSQL提供了内联表值函数TVF


这种类型的“IF”内联函数-sys.objects中的一种不同类型使用“RETURNS TABLE”输出说明符,似乎不能包含BEGIN/END。语法和容差非常严格,但我们看到了良好的优化和性能。@ryk看到的计时表明了这些因素。

从SQL Optimizer的角度来看,这可能是最好的解决方案。您假设高度为整数值。否则,您的中断与OP的查询不匹配。@ryk-在SQL Server 2005上,在一个有110万条记录的表中,我的答案出来得更快。查询计划显示为18%:82%,而统计时间显示为80ms:100ms@Richard-啊,我明白了。。。因为他大于等于155,而我大于154,所以我加了154.5之间的非整数值,这是一个很好的点@ryk/18%和80ms是我的答案。越少越好我认为你在返回声明之前错过了END=1。谢谢分享你的想法!非常感谢Richard的回答!很好的回答。。。由于内联表值函数是解析/缓存的,因此会为它们生成详细的查询计划,而多步骤表值函数(如Cade和Lamak的答案)则不是。另外,他可以通过使用175来解决175和180之间的差距:其中@set='high'和height>175或@set='average'和height>=155和height
--select * from [dbo].[AA]('SDAASF')