2009-01-13 79 views
42

这更是一个语法问题 我想写一个存储过程或函数,我可以嵌入到一个查询,如:TSQL从函数或存储过程返回表

select * from MyBigProcOrFunction 

我我试图定义一个表格函数,但是我不知道该怎么做,因为我在建立tmp表格来处理数据,然后才终于在终点返回。我的代码是:

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

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

回答

58

您不能访问从临时表在一个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 

编辑

基于评论这个问题,这里是我的建议。您想要在另一个查询中加入过程或表值函数的结果。我会告诉你如何做到这一点,然后选择你喜欢的。我将使用来自我的模式之一的示例代码,但您应该能够适应它。两种方法都是先用存储过程解决问题的方法。

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是很多更简洁更容易阅读,既然你不使用probally进行更好一点辅助临时表(性能是我完整的猜测)。

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

6

您需要一种称为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 
+0

你为什么认为他需要这个而不是存储过程? – dkretz 2009-01-13 23:54:14

+0

为什么你认为他需要这个而不是存储过程?你能否得出结论,没有任何进一步的问题? – dkretz 2009-01-13 23:55:33

+1

实际上,您无法将存储过程嵌入到查询中 - 您所能做的最好的做法是从它所选的记录集中插入表中。此外,他似乎特别要求如何编写表值函数的帮助。 – ConcernedOfTunbridgeWells 2009-01-14 00:00:02

9

以此为模板

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.) 
2

就我所知,你不需要(不应该使用)一个函数。存储过程将返回包含返回表格数据的所有SELECT语句的表格数据。

存储过程不使用RETURN语句。

CREATE PROCEDURE名 AS

SELECT INTO东西#temptbl1

.......

SELECT列FROM #temptbln