2009-01-13 18 views
42

Esto es más una cuestión de sintaxis Estoy tratando de escribir un procedimiento almacenado o una función que pueda incrustar en una consulta como:tsql devolver una tabla de un procedimiento de función o tienda

select * from MyBigProcOrFunction 

I Estoy tratando de definir una función tabular pero no entiendo cómo hacerlo a medida que construyo tablas tmp para calcular los datos antes de que finalmente tenga el retorno en la tabla de resultados. Mi marca para mi código es:

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

Si defino una función, ¿cómo la devuelvo como una tabla?

Respuesta

58

No se puede acceder a las tablas temporales de dentro de una función SQL. Usted tendrá que utilizar las variables de tabla tan esencialmente:

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 

Editar

Basándose en los comentarios a esta pregunta aquí es mi recomendación. Desea unir los resultados de una función de procedimiento o de tabla en otra consulta. Te mostraré cómo puedes hacerlo y luego eliges el que prefieras. Voy a usar código de muestra de uno de mis esquemas, pero deberías poder adaptarlo. Ambas son soluciones viables primero con un procedimiento almacenado.

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 

En este caso, debe declarar una tabla temporal o una variable de tabla para almacenar los resultados del procedimiento. Ahora vamos a ver cómo podría hacer esto si estuviera utilizando una UDF

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

Como se puede ver la UDF es mucho más concisa fácil de leer, y PROBally realiza un poco mejor, ya que no se está usando la tabla temporal secundaria (el rendimiento es una suposición completa de mi parte).

Si va a reutilizar su función/procedimiento en muchos otros lugares, creo que la UDF es su mejor opción. La única pega es que tendrá que dejar de usar tablas #Temp y usar variables de tabla. A menos que esté indexando su tabla temporal, no debería haber ningún problema, y ​​utilizará menos tempDb dado que las variables de la tabla se mantienen en la memoria.

+0

Podría ser porque está describiendo un escenario donde un SP es más apropiado que un UDF. Él pregunta qué usar, y el SP es suficiente (y más simple y más cohesivo y más portátil). – dkretz

+0

Suponiendo que en realidad no está pasando parámetros a la función. – JoshBerke

+0

Pensé que sproc sería lo mejor también estoy usando tablas temporales para construir la tabla de datos para devolver, pero cuando intento "seleccionar * desde TheSproc" obtengo un "nombre de objeto no válido" theSproc '" – thiswayup

6

Necesita un tipo especial de función conocida como table valued function. A continuación se muestra un ejemplo algo largo que construye una dimensión de fecha para un depósito de datos. Tenga en cuenta la cláusula returns que define una estructura de tabla. Puede insertar cualquier cosa en la variable de tabla (@DateHierarchy en este caso) que desee, incluida la construcción de una tabla temporal y la copia de los contenidos en ella.

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

¿Por qué crees que necesita esto en lugar de un procedimiento almacenado? – dkretz

+0

¿Por qué crees que necesita esto en lugar de un procedimiento almacenado? ¿Puedes concluir eso sin más preguntas? – dkretz

+1

No puede insertar un procedimiento almacenado en una consulta; lo mejor que puede hacer es insertarlo en una tabla desde un conjunto de registros seleccionado por él. Además, parece que está pidiendo ayuda específicamente sobre cómo escribir una función con valores de tabla. – ConcernedOfTunbridgeWells

9

utilizar esto como una plantilla

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 

que definirá su función. Entonces usted acaba de utilizarlo como cualquier otra tabla:

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

No es necesario (no deben usar) una función en lo que puedo decir. El procedimiento almacenado devolverá datos tabulares de cualquier instrucción SELECT que incluya que devuelva datos tabulares.

Un proceso almacenado no utiliza instrucciones RETURN.

Crear nombre PROCEDIMIENTO AS

cosas SELECT INTO # temptbl1

.......

columnas Selecciona de #temptbln

+3

Si selecciono "de MySproc *" aparece un error que dice "nombre de objeto no válido 'theSproc'" – thiswayup

Cuestiones relacionadas