【问题标题】:tsql returning a table from a function or store proceduresql 从函数或存储过程返回表
【发布时间】:2009-01-13 19:03:19
【问题描述】:

这更像是一个语法问题 我正在尝试编写一个可以嵌入到查询中的存储过程或函数,例如:

select * from MyBigProcOrFunction

我正在尝试定义一个表格函数,但我不明白该怎么做,因为我构建了 tmp 表来计算数据,然后才最终在 endtable 获得返回值。我对代码的标记是:

create function FnGetCompanyIdWithCategories()
returns table
as 
return 
(
select * into a #tempTable from stuff
'
etc
'
select companyid,Company_MarketSector from #tempTables 'the returning table data
)

如果我定义了一个函数,我如何将它作为一个表返回?

【问题讨论】:

  • 直接使用sql命令select * from stuff,我们不能在函数中使用临时表,你的函数语法适合简单的sql查询

标签: sql-server tsql


【解决方案1】:

您无法从 SQL 函数中访问临时表。您将需要如此本质地使用表变量:

ALTER FUNCTION FnGetCompanyIdWithCategories()
RETURNS  @rtnTable TABLE 
(
    -- columns returned by the function
    ID UNIQUEIDENTIFIER NOT NULL,
    Name nvarchar(255) NOT NULL
)
AS
BEGIN
DECLARE @TempTable table (id uniqueidentifier, name nvarchar(255)....)

insert into @myTable 
select from your stuff

--This select returns data
insert into @rtnTable
SELECT ID, name FROM @mytable 
return
END

编辑

基于对这个问题的 cmets,这是我的建议。您希望在另一个查询中加入过程或表值函数的结果。我将向您展示如何做到这一点,然后您选择您喜欢的那个。我将使用我的一个模式中的示例代码,但你应该能够适应它。两者都是首先使用存储过程的可行解决方案。

declare @table as table (id int, name nvarchar(50),templateid int,account nvarchar(50))

insert into @table
execute industry_getall

select * 
from @table 
inner join [user] 
    on account=[user].loginname

在这种情况下,您必须声明一个临时表或表变量来存储过程的结果。现在让我们看看如果您使用的是 UDF,您将如何做到这一点

select *
from fn_Industry_GetAll()
inner join [user] 
    on account=[user].loginname

正如您所见,UDF 更加简洁易读,并且由于您没有使用辅助临时表,因此性能可能会更好一些(性能完全是我的猜测)。

如果您要在许多其他地方重用您的函数/过程,我认为 UDF 是您的最佳选择。唯一的问题是您将不得不停止使用#Temp 表并使用表变量。除非您正在索引临时表,否则应该没有问题,并且您将使用 tempDb 较少,因为表变量保存在内存中。

【讨论】:

  • 可能是因为他在描述一个 SP 比 UDF 更合适的场景。他在问使用哪个,SP 就足够了(而且更简单、更有凝聚力和更便携)。
  • 假设他实际上并没有将参数传递给函数。
  • 我认为 sproc 也是最好的我正在使用临时表来构建要返回的数据表,但是当我尝试“从 TheSproc 中选择 *”时,我得到一个“无效的对象名称” theSproc'"
  • 您不要从 proc 中选择,我知道您可以执行 proc 并将结果放入临时表中。也使用表变量而不是临时表,临时表有一些情况,但通常表变量是更好的选择。
  • 此外,如果您希望此功能可在多个领域重复使用,恕我直言,该功能更好。也就是说,如果这个函数将在许多 s-procs 中重用......否则你的 procs 将需要创建一个临时表来存储过程的结果。
【解决方案2】:

将其用作模板

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE FUNCTION <Table_Function_Name, sysname, FunctionName> 
(
    -- Add the parameters for the function here
    <@param1, sysname, @p1> <data_type_for_param1, , int>, 
    <@param2, sysname, @p2> <data_type_for_param2, , char>
)
RETURNS 
<@Table_Variable_Name, sysname, @Table_Var> TABLE 
(
    -- Add the column definitions for the TABLE variable here
    <Column_1, sysname, c1> <Data_Type_For_Column1, , int>, 
    <Column_2, sysname, c2> <Data_Type_For_Column2, , int>
)
AS
BEGIN
    -- Fill the table variable with the rows for your result set

    RETURN 
END
GO

这将定义您的功能。然后你就可以把它当作任何其他表来使用:

Select * from MyFunction(Param1, Param2, etc.)

【讨论】:

    【解决方案3】:

    您需要一种特殊类型的函数,称为table valued function. 下面是一个为数据仓库构建日期维度的有点冗长的示例。请注意定义表结构的returns 子句。您可以在表变量(本例中为@DateHierarchy)中插入任何您想要的内容,包括构建一个临时表并将内容复制到其中。

    if object_id ('ods.uf_DateHierarchy') is not null
        drop function ods.uf_DateHierarchy
    go
    
    create function ods.uf_DateHierarchy (
           @DateFrom datetime
          ,@DateTo   datetime
    ) returns @DateHierarchy table (
            DateKey           datetime
           ,DisplayDate       varchar (20)
           ,SemanticDate      datetime
           ,MonthKey          int     
           ,DisplayMonth      varchar (10)
           ,FirstDayOfMonth   datetime
           ,QuarterKey        int
           ,DisplayQuarter    varchar (10)
           ,FirstDayOfQuarter datetime
           ,YearKey           int
           ,DisplayYear       varchar (10)
           ,FirstDayOfYear    datetime
    ) as begin
        declare @year            int
               ,@quarter         int
               ,@month           int
               ,@day             int
               ,@m1ofqtr         int
               ,@DisplayDate     varchar (20)
               ,@DisplayQuarter  varchar (10)
               ,@DisplayMonth    varchar (10)
               ,@DisplayYear     varchar (10)
               ,@today           datetime
               ,@MonthKey        int
               ,@QuarterKey      int
               ,@YearKey         int
               ,@SemanticDate    datetime
               ,@FirstOfMonth    datetime
               ,@FirstOfQuarter  datetime
               ,@FirstOfYear     datetime
               ,@MStr            varchar (2)
               ,@QStr            varchar (2)
               ,@Ystr            varchar (4)
               ,@DStr            varchar (2)
               ,@DateStr         varchar (10)
    
    
        -- === Previous ===================================================
        -- Special placeholder date of 1/1/1800 used to denote 'previous'
        -- so that naive date calculations sort and compare in a sensible
        -- order.
        --
        insert @DateHierarchy (
             DateKey
            ,DisplayDate
            ,SemanticDate
            ,MonthKey
            ,DisplayMonth
            ,FirstDayOfMonth
            ,QuarterKey
            ,DisplayQuarter
            ,FirstDayOfQuarter
            ,YearKey
            ,DisplayYear
            ,FirstDayOfYear
        ) values (
             '1800-01-01'
            ,'Previous'
            ,'1800-01-01'
            ,180001
            ,'Prev'
            ,'1800-01-01'
            ,18001
            ,'Prev'
            ,'1800-01-01'
            ,1800
            ,'Prev'
            ,'1800-01-01'
        )
    
        -- === Calendar Dates =============================================
        -- These are generated from the date range specified in the input
        -- parameters.
        --
        set @today = @Datefrom
        while @today <= @DateTo begin
    
            set @year = datepart (yyyy, @today)
            set @month = datepart (mm, @today)
            set @day = datepart (dd, @today)
            set @quarter = case when @month in (1,2,3) then 1
                                when @month in (4,5,6) then 2
                                when @month in (7,8,9) then 3
                                when @month in (10,11,12) then 4
                            end
            set @m1ofqtr = @quarter * 3 - 2 
    
            set @DisplayDate = left (convert (varchar, @today, 113), 11)
            set @SemanticDate = @today
            set @MonthKey = @year * 100 + @month
            set @DisplayMonth = substring (convert (varchar, @today, 113), 4, 8)
            set @Mstr = right ('0' + convert (varchar, @month), 2)
            set @Dstr = right ('0' + convert (varchar, @day), 2)
            set @Ystr = convert (varchar, @year)
            set @DateStr = @Ystr + '-' + @Mstr + '-01'
            set @FirstOfMonth = convert (datetime, @DateStr, 120)
            set @QuarterKey = @year * 10 + @quarter
            set @DisplayQuarter = 'Q' + convert (varchar, @quarter) + ' ' +
                                        convert (varchar, @year)
            set @QStr = right ('0' + convert (varchar, @m1ofqtr), 2)   
            set @DateStr = @Ystr + '-' + @Qstr + '-01' 
            set @FirstOfQuarter = convert (datetime, @DateStr, 120)
            set @YearKey = @year
            set @DisplayYear = convert (varchar, @year)
            set @DateStr = @Ystr + '-01-01'
            set @FirstOfYear = convert (datetime, @DateStr)
    
    
            insert @DateHierarchy (
                 DateKey
                ,DisplayDate
                ,SemanticDate
                ,MonthKey
                ,DisplayMonth
                ,FirstDayOfMonth
                ,QuarterKey
                ,DisplayQuarter
                ,FirstDayOfQuarter
                ,YearKey
                ,DisplayYear
                ,FirstDayOfYear
            ) values (
                 @today
                ,@DisplayDate
                ,@SemanticDate
                ,@Monthkey
                ,@DisplayMonth
                ,@FirstOfMonth
                ,@QuarterKey
                ,@DisplayQuarter
                ,@FirstOfQuarter
                ,@YearKey
                ,@DisplayYear
                ,@FirstOfYear
            )
    
            set @today = dateadd (dd, 1, @today)
        end
    
        -- === Specials ===================================================
        -- 'Ongoing', 'Error' and 'Not Recorded' set two years apart to
        -- avoid accidental collisions on 'Next Year' calculations.
        --
        insert @DateHierarchy (
             DateKey
            ,DisplayDate
            ,SemanticDate
            ,MonthKey
            ,DisplayMonth
            ,FirstDayOfMonth
            ,QuarterKey
            ,DisplayQuarter
            ,FirstDayOfQuarter
            ,YearKey
            ,DisplayYear
            ,FirstDayOfYear
        ) values (
             '9000-01-01'
            ,'Ongoing'
            ,'9000-01-01'
            ,900001
            ,'Ong.'
            ,'9000-01-01'
            ,90001
            ,'Ong.'
            ,'9000-01-01'
            ,9000
            ,'Ong.'
            ,'9000-01-01'
        )
    
        insert @DateHierarchy (
             DateKey
            ,DisplayDate
            ,SemanticDate
            ,MonthKey
            ,DisplayMonth
            ,FirstDayOfMonth
            ,QuarterKey
            ,DisplayQuarter
            ,FirstDayOfQuarter
            ,YearKey
            ,DisplayYear
            ,FirstDayOfYear
        ) values (
             '9100-01-01'
            ,'Error'
            ,null
            ,910001
            ,'Error'
            ,null
            ,91001
            ,'Error'
            ,null
            ,9100
            ,'Err'
            ,null
        )
    
        insert @DateHierarchy (
             DateKey
            ,DisplayDate
            ,SemanticDate
            ,MonthKey
            ,DisplayMonth
            ,FirstDayOfMonth
            ,QuarterKey
            ,DisplayQuarter
            ,FirstDayOfQuarter
            ,YearKey
            ,DisplayYear
            ,FirstDayOfYear
        ) values (
             '9200-01-01'
            ,'Not Recorded'
            ,null
            ,920001
            ,'N/R'
            ,null
            ,92001
            ,'N/R'
            ,null
            ,9200
            ,'N/R'
            ,null
        )
    
        return
    end
    
    go
    

    【讨论】:

    • 你认为他为什么需要这个而不是存储过程?
    • 为什么你认为他需要这个而不是存储过程?如果没有任何进一步的问题,你能得出结论吗?
    • 您实际上不能将存储过程嵌入到查询中 - 您能做的最好的事情就是从它选择的记录集中插入到表中。此外,他似乎非常特别地寻求有关如何编写表值函数的帮助。
    【解决方案4】:

    据我所知,您不需要(不应该使用)功能。存储过程将从您包含的任何返回表格数据的 SELECT 语句中返回表格数据。

    存储过程不使用 RETURN 语句。

     CREATE PROCEDURE name
     AS
    
     SELECT stuff INTO #temptbl1
    
     .......
    
    
     SELECT columns FROM #temptbln
    

    【讨论】:

    • 如果我“从 MySproc 中选择 *”,我会收到一条错误消息“无效的对象名称 'theSproc'”
    • 就我而言,我还需要返回状态码和错误消息,这肯定是要走的路。基本上,返回的结果是表更新的副产品,因此不需要额外的选择。但在纯参数化复杂查询的情况下,TVF 听起来更合适。
    猜你喜欢
    • 2016-07-03
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 2016-11-03
    相关资源
    最近更新 更多