web-dev-qa-db-fra.com

Le serveur SQL crée une fonction temporaire en tant que CTE

J'ai besoin de créer une fonction temporaire, pour une utilisation dans une requête plus importante, mais je n'ai pas d'autorisations de création sur la base de données (sauf pour les tables #TEMP).

Existe-t-il un moyen d'utiliser un CTE ou une requête #temp à cette fin? Peut-être que je manque quelque chose de vraiment simple ici.

Exemple (à quoi il pourrait ressembler): -

with add1(x) as
  return x+1

select add1(v.Value1), add1(v.Value2)
from Values v

Tableau des valeurs

Id Value1 Value2
1  1       4
2  2       5
3  3       6

ÉDITER

Selon la réponse d'Aaron Bertrand, j'ai réussi à faire fonctionner quelque chose.

CREATE TABLE #myTempTable
(
  id int identity(1,1) primary key, 
  amount  int, 
  col1  varchar(10),
  col2 varchar(4)

);
-- quite a few more cols in my actual temp table,  
-- omitted to show the real issue

INSERT #myTempTable(amount,col1, col2) VALUES(10,'a1', 'b1'),(15,'a2','b2');

;WITH processed AS 
(
  SELECT * FROM #myTempTable AS r
  UNPIVOT (Result FOR [Value] IN r.Amount) unp
  CROSS APPLY
  ( 

     /******** COMPLEX FUNCTION HERE ********/
     /**** Applies to output of unpivot *****/

     SELECT unp.Result + 10 [Processed_amount]

  ) AS a
  --PIVOT (max(orig) FOR Value IN ( amount)) AS p2
)

select top 10 [Processed_amount], * from processed

Le dernier PIVOT gâche cependant les résultats. Je me demandais pourquoi cela était nécessaire.

J'essaie toujours d'enrouler ma tête autour des différentes parties de UNPIVOT et PIVOT.


EDIT2

Veuillez voir ma réponse,
Je l'ai fait fonctionner où nous n'avons besoin que d'une colonne à traiter ..

4
heyNow

Pour répliquer ce type de code, sans créer de fonction:

CREATE FUNCTION dbo.add1(@x int)
RETURNS int
AS
BEGIN
  RETURN (SELECT @x + 1);
END
GO

SELECT dbo.add1(v.Value1), dbo.add1(v.Value2)
FROM (VALUES(1,2),(3,4)) AS v(Value1, Value2);

Vous pouvez utiliser CROSS APPLY:

SELECT z.v1, z.v2
FROM (VALUES(1,2),(3,4)) AS v(Value1, Value2)
CROSS APPLY
(
  SELECT v.Value1 + 1, v.Value2 + 1
) AS z(v1,v2);

Si la fonction est extrêmement compliquée et que vous ne voulez pas la répéter, et c'est le problème réel, vous pouvez essayer cette solution. Il est complexe mais vous permet de n'écrire la fonction qu'une seule fois. Si vous devez l'étendre à plus de deux colonnes, cela devient plus compliqué.

CREATE TABLE #vals
(
  id int identity(1,1) primary key, 
  a  int, 
  b  int
);

INSERT #vals(a,b) VALUES(1,2),(15,16);

;WITH vals AS 
(
  SELECT * FROM #vals AS v
  UNPIVOT (Result FOR [Value] IN (a,b)) unp
  CROSS APPLY
  ( 

     /******** COMPLEX FUNCTION HERE ********/
     /**** Applies to output of unpivot *****/
     SELECT unp.Result + 10

  ) AS new(orig)
  PIVOT (MAX(orig) FOR Value IN ([a],[b])) AS p2
)
SELECT v1.id, 
  OriginalValue1 = v1.Result, 
  Value1 = v1.a, 
  OriginalValue2 = v2.Result, 
  Value2 = v2.b 
FROM vals AS v1 
JOIN vals AS v2 ON v1.id = v2.id
AND v1.a IS NOT NULL
AND v2.b IS NOT NULL;

GO
DROP TABLE #vals;

Ou vous pouvez demander les autorisations pour créer votre fonction quelque part.

5
Aaron Bertrand

Je mets plus de travail dans une réponse au lieu d'encombrer la vraie question ..

J'ai pu progresser grâce à Aaron Bertrand's réponse, donc je l'ai marqué comme réponse.
.

Il s'avère que si une seule colonne est nécessaire pour être traitée à l'aide de cette fonction locale, nous n'avons pas réellement besoin de UNPIVOT et PIVOT et pouvons gérer avec juste un CROSS APPLY

CREATE TABLE #myTempTable
(
  id int identity(1,1) primary key, 
  Amount  int, 
  Col1  varchar(10),
  Col2 varchar(4)

);
-- quite a few more cols in my actual temp table,  
-- omitted to show the real issue

INSERT #myTempTable(Amount,Col1, Col2) VALUES(10,'a1', 'b1'),(15,'a2','b2');

;WITH p AS 
(
  SELECT * FROM #myTempTable AS q
  CROSS APPLY
  ( 

     /******** COMPLEX FUNCTION HERE ********/
     /**** Applies to output of unpivot *****/

     SELECT q.Amount + 10 [Processed_amount]

  ) AS r      
)
select top 10 [Processed_amount], * from p
1
heyNow