2009-01-13 80 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