2012-06-29 25 views
7

Estoy intentando crear una función según mis requisitos.Crear, colocar e insertar una tabla temporal en una función definida por el usuario

Pero, cuando estoy creando o dejar #tempTable, se da un error como:

uso inválido de un operador efectuar lado 'objeto gota' dentro de una función

Mi entendimiento es que no podemos tener create, drop o insert operaciones en #temptable en una función.

¿Es correcto?

Mi SQL:

CREATE FUNCTION [dbo].[RT_ResultFunction] 
(
    Id VARCHAR(4000) 
) 
RETURNS @RT_ResultFunction TABLE 
( 
    Id VARCHAR(20) 
    , Name varchar(20) 
    ,Balance Int 
) 
AS 
BEGIN 
    IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL 
     DROP TABLE #tempTable 

    SELECT Id, COUNT(Balance) 
    INTO #tempTable 
    'Balance' FROM Table1 

    INSERT @RT_ResultFunction 
     SELECT T1.ID,T1,NAME,T2,Balance 
     FROM Table2 T1, 
       #tempTable T2 
     WHERE T1.ID = T2.ID 

    RETURN 
END 
+1

Bit confundido acerca de su SQL. Cómo seleccionar desde #tempTable después de haberlo descartado, nunca se vuelve a crear. –

+0

Busque la publicación actualizada –

+0

Si desea ayuda para resolver este problema, explique el punto de la #temptable dentro de la función. También qué hacer con el parámetro Id. –

Respuesta

19

Eso es correcto - no se puede tener secundarios efectuar declaraciones:

A partir de aquí: http://msdn.microsoft.com/en-us/library/aa175085(v=sql.80).aspx

Las declaraciones en un bloque BEGIN ... END no puede tener cualquier efecto secundario Los efectos secundarios de la función son cambios permanentes en el estado de un recurso que tiene un alcance fuera de la función como una modificación en una tabla de base de datos. Los únicos cambios que se pueden realizar mediante las declaraciones en la función son los cambios a los objetos locales de la función , como los cursores locales o las variables. Las modificaciones a tablas de base de datos, operaciones en cursores que no son locales a la función , envío de correo electrónico, intento de modificación de catálogo y generando un conjunto de resultados devuelto al usuario son ejemplos de acciones que no se pueden realizar en Una función.

Lo que se puede encontrar, incluso sin su declaración DROP, es que cualquier intento de acceder a una tabla temporal le dará el mensaje (como un SELECT ... INTO #TMP):

No se puede acceder a las tablas temporales desde dentro una función

Como señala @Dems, puede usar las variables de la tabla. Debido a que estas son variables, tienen un alcance dentro de la función y, por lo tanto, no son efecto secundario.

Su función puede ejecutarse:

... 

BEGIN 
    DECLARE @tempTable table (id varchar(20), rows int) 

    insert @tempTable 
    SELECT Id, COUNT(Balance) 
    FROM Table1 

    INSERT @RT_ResultFunction 
     SELECT T1.ID,T1,NAME,T2,Balance 
     FROM Table2 T1, 
       @tempTable T2 
     WHERE T1.ID = T2.ID 

    RETURN END 

no han sido evaluados ni nada, pero se obtiene la esencia.

+3

Pero puede usar variables de tabla. Lo cual sería un hecho útil para agregar a su respuesta para ayudar al OP a resolver su problema * (en lugar de simplemente saber por qué es un problema) *;) – MatBailie

+0

@Dems: Buen punto - actualizado con más información. –

+0

Después de leer la documentación de MSDN, me pregunté: ¿es posible modificar datos reales de una tabla ('INSERT' /' UPDATE'/'DELETE') llamando a' Stored Procedure' en su 'function'? Supongo que no puedes, pero prefiero estar seguro de que se producirá un error. ¿Podrías decirme si lo sabes? :) –

2

No tengo idea de por qué necesita una tabla #temp en esta función o por qué es una TVF multi-declaración en primer lugar.El siguiente será mucho más eficiente (aunque no entiendo el propósito del parámetro @Id):

CREATE FUNCTION [dbo].[RT_ResultFunction] 
(
    @Id VARCHAR(4000) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    (
    SELECT T2.ID, T2.NAME, T1.Balance 
    FROM 
    (
     SELECT ID, Balance = COUNT(Balance) 
     FROM dbo.Table1 
     GROUP BY ID 
    ) AS T1 
    INNER JOIN dbo.Table2 AS T2 
    ON T1.ID = T2.ID 
); 

Como Jon señaló, que piensan también podría ser reescrita como sigue, y es en realidad cómo empecé a escribirlo, pero no tengo ninguna manera de confirmar si alguno de estos en realidad devuelve los datos que está intentando volver:

CREATE FUNCTION [dbo].[RT_ResultFunction] 
(
    @Id VARCHAR(4000) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    (
    SELECT T2.ID, T2.NAME, Balance = COUNT(T1.Balance) 
    FROM dbo.Table1 AS T1 
    INNER JOIN dbo.Table2 AS T2 
    ON T1.ID = T2.ID 
    GROUP BY T2.ID, T2.NAME 
); 
+0

Es cierto: la tabla temporal es un poco "de lujo" en este caso, pero es un punto útil para cubrir en cualquier caso. (también necesita un alias en el recuento interno). –

+0

@Jon ID y Name vienen de diferentes tablas. No sé el esquema o los datos, así que traté de mantenerme fiel a la consulta original. –

0

Quitar # en lugar de utilizar @ no he probado otro aspecto

Cuestiones relacionadas