Avant de poster, j'ai lu quelques articles sur le développement des fonctions USD, mais je n'ai pas trouvé de solutions à mon problème ... qui se présente comme suit:
J'ai une base de données très simple, qui stocke les joueurs de basket et se compose de la colonne ID, Age, Height et Name. Ce que je voudrais faire est d'implémenter une fonction 'height' avec un paramètre @set varchar (10), qui dépend d'un @set pour déclencher différentes instructions de sélection
ce que j'essayais d'implémenter était en psuedo-code:
CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS TABLE
AS
BEGIN
IF (@set = 'tall')
SELECT * from player where height > 180
ELSE IF (@set = 'average')
SELECT * from player where height >= 155 and height <=175
ELSE IF (@set = 'low')
SELECT * from player where height < 155
END
Quelqu'un pourrait-il me donner un indice sur la manière de le mettre en œuvre?
La forme la plus simple est toujours la meilleure
CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS TABLE
AS RETURN
SELECT * from player
where ((@set = 'tall' and height > 180)
or (@set = 'average' AND height >= 155 and height <=175)
or (@set = 'low' AND height < 155))
GO
Ce formulaire est appelé fonction de table INLINE, ce qui signifie que SQL Server est libre de le développer pour joindre le lecteur directement à d’autres tables en ligne d’une requête plus importante, ce qui lui permet d’exécuter infiniment1 mieux qu'une fonction valorisée de table multi-instructions.
Vous préférerez peut-être cela, afin que vos gammes soient complètes (vous avez un écart entre 175 et 180)
where ((@set = 'tall' and height > 180)
or (@set = 'average' AND height >= 155 and height <= 180)
or (@set = 'low' AND height < 155))
SQL Server s'occupe de court-circuiter les branches lorsque la variable @set est analysée.
1 exagération, mais seulement légèrement
Tu étais proche. L'utilisation d'une fonction table multi-instruction nécessite que la table de retour soit spécifiée et renseignée dans la fonction:
CREATE FUNCTION [dbo].[age](@set varchar(10))
RETURNS @Players TABLE
(
-- Put the players table definition here
)
AS
BEGIN
IF (@set = 'tall')
INSERT INTO @Players SELECT * from player where height > 180
ELSE IF (@set = 'average')
INSERT INTO @Players SELECT * from player where height >= 155 and height <=175
ELSE IF (@set = 'low')
INSERT INTO @Players SELECT * from player where height < 155
RETURN -- @Players (variable only required for Scalar functions)
END
Je recommanderais d'utiliser une TVF intégrée, comme le montre la réponse de Richard. Il peut déduire le retour de table de votre déclaration.
Notez également que les TVF multi-instructions et inline sont vraiment très différents. Un fichier TVF intégré est moins une boîte noire que l'optimiseur et ressemble plutôt à une vue paramétrée en ce sens que l'optimiseur peut réorganiser les éléments avec d'autres tables et vues dans le même plan d'exécution.
Pourquoi codez-vous en dur, créez une table des hauteurs puis saisissez toutes les hauteurs valables pour la plage
SELECT * from player p
join Heights h on p.height between h.heightStart and h.heightEnd
WHERE h.height = @set
Cela devrait marcher.
SELECT * FROM player
WHERE
height > CASE
WHEN @set = 'tall' THEN 180
WHEN @set = 'average' THEN 154
WHEN @set = 'low' THEN 0
END
Je vais laisser le cas pour votre plus grand plaisir.
Quelque chose comme ça:
CREATE FUNCTION [dbo].[Age](@set VARCHAR(10))
RETURNS @Players TABLE
(
playerId INT,
Name VARCHAR(50)
)
AS
BEGIN
INSERT INTO @Players
SELECT playerId, Name
FROM player
WHERE CASE WHEN @set = 'tall' AND height > 180 THEN 1
WHEN @set = 'average' AND height BETWEEN 155 AND 180 THEN 1
WHEN @set = 'low' AND height < 155 THEN 1 ELSE 0 END = 1
RETURN
END
Nous pouvons utiliser la fonction de valeur Table de la manière suivante avec des conditions IF dessus.
CREATE function [dbo].[AA]
(
@abc varchar(10)
)
Returns @mytable table
(
supname nvarchar(10), [add] nvarchar(10)
)
AS
begin
-- lOAD WHATEVER THINGS YOU REQUIRED INTO THIS DYNAMIC TABLE
if (@abc ='hh')
insert into @mytable (supname, [add]) values ('hh','gg'+ @abc)
else
insert into @mytable (supname, [add]) values ('else','gg'+ @abc)
return
end
--select * from [dbo].[AA]('SDAASF')
Selon Itzik Ben-Gan dans son livre "TSQL Querying" (Itzik Ben-Gan et al , (c) 2015, Microsoft Press, ISBN 978-0-7356-8504-8, p. 215) ".. . Je trouve que les TVF intégrés sont un excellent outil, permettant d’encapsuler la logique et de pouvoir être réutilisés sans aucun problème de performance des fonctions UDF ... "
Il ajoute que si vous avez besoin de " ... une expression de table réutilisable telle qu'une vue, vous devez également transmettre des paramètres d'entrée à l'expression de table ... TSQL fournit des fonctions de table inline (TVF). "
Ce type de 'IF' ( inline function - un type distinct dans sys.objects ) utilise le spécificateur de sortie 'RETURNS TABLE' et ne peut apparemment pas contenir BEGIN/END. La syntaxe et les tolérances sont très restrictives, mais nous constatons une optimisation et des performances satisfaisantes. Ces facteurs sont indiqués par les timings observés par @ryk.