sql2005中 表值函数是啥

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql2005中 表值函数是啥相关的知识,希望对你有一定的参考价值。

表值函数是数据库中一种较为特殊的函数类型,它的返回值不再只是一个数值或一个字符串,而是一张数据表。也就是说表值函数返回的是
table
数据类型。对于内联表值函数,没有函数主体;表是单个
SELECT
语句的结果集。使用表值函数的时候,把函数直接当成是表或视图使用,表值函数的参数传入方法与标量函数没有区别。
参考技术A 表值函数是指返回结果是一个二维表的函数。你可以将表函数放在查询的from子句中,当做一个表或者视图使用。

如何在 SQL Server 的表值函数中使用 CTE 语句

【中文标题】如何在 SQL Server 的表值函数中使用 CTE 语句【英文标题】:How to use a CTE statement in a table-valued function in SQL Server 【发布时间】:2013-02-11 17:59:13 【问题描述】:

我了解到某些版本的 Microsoft OLE DB Provider for SQL Server(主要在 Windows XP 上)不支持WITH 语句。因此,我决定将我的 SQL 语句移动到一个表值函数中,并从我的应用程序中调用它。现在,我被困住了。我应该如何将INSERT INTO 语句与WITH 一起使用?这是到目前为止我提供的代码,但 SQL Server 不喜欢它... :-(

CREATE FUNCTION GetDistributionTable 
(
    @IntID int,
    @TestID int,
    @DateFrom datetime,
    @DateTo datetime
)
RETURNS 
@Table_Var TABLE 
(
    [Count] int, 
    Result float
)
AS
BEGIN
INSERT INTO @Table_Var ([Count], Result) WITH T(Result)
     AS (SELECT ROUND(Result - AVG(Result) OVER(), 1)
         FROM RawResults WHERE IntID = @IntID AND DBTestID = @TestID AND Time >= @DateFrom AND Time <= @DateTo)
SELECT COUNT(*) AS [Count],
       Result
FROM   T
GROUP  BY Result

    RETURN 
END
GO

【问题讨论】:

【参考方案1】:

表值函数中 CTE 的语法为:

CREATE FUNCTION GetDistributionTable 
(
    @IntID int,
    @TestID int,
    @DateFrom datetime,
    @DateTo datetime
)
RETURNS TABLE
AS
RETURN  
(
    WITH cte AS
    (
        SELECT ROUND(Result - AVG(Result) OVER(), 1) Result
        FROM   RawResults 
        WHERE  IntID = @IntID 
        AND    DBTestID = @TestID 
        AND    Time >= @DateFrom 
        AND Time <= @DateTo    
    )

    SELECT  COUNT(*) AS [Count],
            Result
    FROM    cte
    GROUP  BY 
            Result
)
GO

如果可能,您也可以省略 CTE(WITH 语句),而是创建一个使用子查询的内联表值函数:

CREATE FUNCTION GetDistributionTable 
(
    @IntID int,
    @TestID int,
    @DateFrom datetime,
    @DateTo datetime
)
RETURNS TABLE
AS
RETURN  
(
    SELECT  COUNT(*) AS [Count],
            Result
    FROM    (
                 SELECT ROUND(Result - AVG(Result) OVER(), 1) Result
                 FROM   RawResults 
                 WHERE  IntID = @IntID 
                 AND    DBTestID = @TestID 
                 AND    Time >= @DateFrom 
                 AND Time <= @DateTo    
    ) t
    GROUP  BY 
            Result
)
GO

您的示例似乎使用了多语句 TVF(插入和选择),当您有选择时尝试使用内联 TVF,因为多语句 TVF 会阻止查询优化器选择更好的执行计划(解释了性能差异here)

【讨论】:

如果您的 CTE 是递归的,您可能无法将其重写为子查询表单,因此 CTE 表单可能不仅仅是一个简单的口味问题。当然,如果您不小心,递归 CTE 可能会使优化器失效:blogs.msdn.com/b/sqlcat/archive/2011/04/28/…> 所以习惯用;前面加上cte的一部分。 @JSS - SQL Server 中的语句应该以分号结束。到目前为止,这仅在有限的区域内强制执行,而不会破坏某些结构的向后兼容性 - 尤其是较新的结构 - 要求前面的语句以分号终止。 CTE 只是其中的一个例子。在 CTE 前面加上分号是避免这种语言要求的一种有点笨拙的方法 - 在这种情况下,如果没有先前的语句需要终止,它会导致混淆。始终如一地终止您的陈述可以避免这种情况。 只是为了记住一些有趣的事情:根据此链接,我们不能在 udf 中使用 maxrecursion 0:social.msdn.microsoft.com/Forums/sqlserver/en-US/… @RichardAbey-Nesbit 值得注意的是,在单语句UDF(最后一个括号之前)的结尾查询中添加分号将被解释为多语句并导致错误。【参考方案2】:
CTE with if else in UDF 

USE [SchoolDB]
GO

/****** Object:  UserDefinedFunction [dbo].[GetDistributionTable]    Script Date: 24-08-2019 05:17:55 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO





alter  FUNCTION [dbo].[GetDistributionTable] 
(
   @DepartmentName varchar(50) = 'Production'
)
RETURNS 
@Table_Var TABLE 
(   NUM int IDENTITY(1,1),
    [ParentEmployeeKey] int, 
    Result float
)
AS
BEGIN
Declare @Table_Vars table
(
    [ParentEmployeeKey] int, 
    Result float
);
insert into @Table_Vars([ParentEmployeeKey])
select COUNT(1) Result from 
        [SchoolDB].[dbo].[DimEmployee] where DepartmentName = @DepartmentName
if(@@rowcount >0)
begin
WITH T 
    AS (    
        select [ParentEmployeeKey],COUNT(1) Result from 
        [SchoolDB].[dbo].[DimEmployee] where DepartmentName = @DepartmentName
        group by [ParentEmployeeKey]
   )
  INSERT INTO @Table_Var ([ParentEmployeeKey], Result)
  SELECT COUNT(*) AS [Count],
       Result
  FROM   T
  GROUP  BY Result
end
else

 WITH T 
    AS (    
        select [ParentEmployeeKey],COUNT(1) Result from 
        [SchoolDB].[dbo].[DimEmployee] where DepartmentName = @DepartmentName
        group by [ParentEmployeeKey]
   )
  INSERT INTO @Table_Var ([ParentEmployeeKey], Result)
  SELECT COUNT(*) AS [Count],
       Result
  FROM   T
  GROUP  BY Result
  RETURN 
END



GO

【讨论】:

【参考方案3】:

喜欢这个..

CREATE FUNCTION GetDistributionTable 
(
    @IntID int,
    @TestID int,
    @DateFrom datetime,
    @DateTo datetime
)
RETURNS 
@Table_Var TABLE 
(
    [Count] int, 
    Result float
)
AS
BEGIN
  WITH T 
    AS (    
        select Ticket_Id,COUNT(1) Result from 
        Customer_Survey
        group by MemberID,SiteId,Ticket_Id
   )
  INSERT INTO @Table_Var ([Count], Result)
  SELECT COUNT(*) AS [Count],
       Result
  FROM   T
  GROUP  BY Result
  RETURN 
END
GO

【讨论】:

如果可能的话,应该同时测试您展示的多语句函数以及单语句 RETURNS TABLE 函数,因为后者可以内联,因此有时具有更好的性能(请参阅 Ivan G 答案底部的链接)。然而,像往常一样,这一切都取决于--有时,虽然很少,但使用多语句功能会更快。

以上是关于sql2005中 表值函数是啥的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver2005 表值函数

SQL 2005 - 表值函数编译正常,但选择时在 .. 附近抛出不正确的语法

通过在 SQL Server 2000 中传递变量参数来加入表值函数

使用 SQL Server 2005 完成 SQL 代码的好工具是啥? [关闭]

sql 2005 聚合函数

SQL Server 2005 上的“警告:没有看到 LOP_CKPT_END”消息是啥意思?