4

J'ai besoin d'aide pour cette fonction à valeur scalaire.Besoin d'aide avec la fonction à valeur scalaire dans SQL Server 2008

Ce que je veux faire est de retourner la valeur que j'obtiens dans MaxValue sur la ligne max(Value) AS MaxValue.

La requête fonctionne et ne retournera qu'une valeur si ItemId et ListPropertyId existe, mais je ne suis pas en mesure d'en créer une fonction.

CREATE FUNCTION GetLpivMax 
(
    -- Add the parameters for the function here 
    @ItemId int, 
    @ListPropertyId int 
) 
RETURNS int 
AS 
BEGIN 
    DECLARE @output INT; 
    WITH U AS (
    SELECT i.Id AS ItemId, 
      lpiv.Value, 
      lp.Id AS ListPropertyId 
     FROM ListPropertyItemValues lpiv 
     JOIN ListPropertyItems lpi ON lpi lpi.Id = lpiv.ListPropertyItemId 
     JOIN ListProperties lp ON lp.Id = lpi.ListPropertyId 
     JOIN Items i ON i.Id = lpiv.ItemId) 
    SELECT @output = MAX(u.value) 
     FROM U u 
    WHERE u.listpropertyid = @ListPropertyId 
     AND u.itemid = @ItemId 
    GROUP BY u.listpropertyid, u.itemid 

    RETURN @output 
END 
GO 
+0

+1: Pour utiliser les alias de table, mais s'il vous plaît ne pas afficher l'onglet Code délimité SO - il encule vraiment la sortie et permet de les corriger une douleur. Pour plus d'informations sur la syntaxe markdown, voir: http: // stackoverflow.com/editing-help –

Répondre

3

J'ai upvoted votre question, mais je n'aime pas les réponses. Vous devriez changer votre code à une fonction de table inline à la place. Ce code sera considéré comme procédural à chaque fois, et ce n'est qu'une seule requête.

j'écrit à ce sujet à http://msmvps.com/blogs/robfarley/archive/2009/12/05/dangers-of-begin-and-end.aspx, mais je vais vous expliquer rapidement ce que vous devez faire:

CREATE FUNCTION GetLpivMax 
( 
    -- Add the parameters for the function here 
    @ItemId int, 
    @ListPropertyId int 
) 
RETURNS TABLE AS 
RETURN (
SELECT MAX(lpiv.Value) as LpivMax 
    FROM ListPropertyItemValues lpiv 
    JOIN ListPropertyItems lpi ON lpi.Id = lpiv.ListPropertyItemId 
    JOIN ListProperties lp ON lp.Id = lpi.ListPropertyId 
    JOIN Items i ON i.Id = lpiv.ItemId 
    WHERE lp.id = @ListPropertyId 
    AND i.id = @ItemId 
GROUP BY lp.id, i.id 
); 

maintenant l'utiliser comme ceci:

SELECT ip.*, m.LpivMax 
FROM ItemsAndProperties ip 
CROSS APPLY 
dbo.GetLpivMax(ip.ItemID, ip.ListPropertyID) m 
; 

Vous pouvez utiliser OUTER APPLY si vous ne ne veux pas éliminer les lignes de votre ensemble de données. Vous pouvez ajouter des agrégats supplémentaires qui seront complètement ignorés si vous ne les consultez pas. Mais par-dessus tout, l'Optimiseur de requêtes simplifiera votre requête, de sorte que, s'il peut éviter de faire une grande partie du travail, il le fera.

Hope this helps ...

+0

Cool. Je n'en avais aucune idée :) – Mickel

0

Ajouter ces lignes à votre code et il devrait fonctionner:

Ajouter ce au début (juste après BEGIN)

DECLARE @output int 

Ajoutez ceci à la fin (juste avant la fin)

RETURN @output 

Mettez tous ensemble comme ceci:

CREATE FUNCTION GetLpivMax 
(
    -- Add the parameters for the function here 
    @ItemId int, 
    @ListPropertyId int 
) 
RETURNS int 
AS 
BEGIN 

    DECLARE @output INT; 

    WITH U AS (
    SELECT i.Id AS ItemId, 
      lpiv.Value, 
      lp.Id AS ListPropertyId 
     FROM ListPropertyItemValues lpiv 
     JOIN ListPropertyItems lpi ON lpi lpi.Id = lpiv.ListPropertyItemId 
     JOIN ListProperties lp ON lp.Id = lpi.ListPropertyId 
     JOIN Items i ON i.Id = lpiv.ItemId) 

    SELECT @output = MAX(u.value) 
     FROM U u 
    WHERE u.listpropertyid = @ListPropertyId 
     AND u.itemid = @ItemId 
    GROUP BY u.listpropertyid, u.itemid 

    RETURN @output 
END 
GO 
2

Utilisation:

DECLARE @output INT 

BEGIN 
    WITH U AS (
    SELECT i.Id AS ItemId, 
      lpiv.Value, 
      lp.Id AS ListPropertyId 
     FROM ListPropertyItemValues lpiv 
     JOIN ListPropertyItems lpi ON lpi.Id = lpiv.ListPropertyItemId 
     JOIN ListProperties lp ON lp.Id = lpi.ListPropertyId 
     JOIN Items i ON i.Id = lpiv.ItemId) 
    SELECT @output = MAX(u.value) 
     FROM U u 
    WHERE u.listpropertyid = @ListPropertyId 
     AND u.itemid = @ItemId 
    GROUP BY u.listpropertyid, u.itemid 

    RETURN @output 
END 

Le SELECT @output = MAX(u.value) attribue la valeur à la variable @output, alors vous devez le retourner en utilisant la syntaxe RETURN. Une alternative serait de définir un paramètre out, en fonction de vos besoins.

J'ai également converti votre syntaxe JOIN de ANSI-89 à ANSI-99. Il s'agit d'une performance équivalente, mais mieux adaptée aux LEFT JOINs que l'ancienne syntaxe et largement prise en charge sur d'autres bases de données (ce qui la rend plus portable en cas de besoin).

Aussi, essayez:

SELECT @output = MAX(lpiv.Value) 
    FROM ListPropertyItemValues lpiv 
    JOIN ListPropertyItems lpi ON lpi.Id = lpiv.ListPropertyItemId 
    JOIN ListProperties lp ON lp.Id = lpi.ListPropertyId 
    JOIN Items i ON i.Id = lpiv.ItemId 
    WHERE lp.id = @ListPropertyId 
    AND i.id = @ItemId 
GROUP BY lp.id, i.id 

Je ne pense pas que vous avez besoin du CTE ...

+0

+1 Cependant, si le BEGIN est celui de la fonction, alors la déclaration de la variable @output ne devrait-elle pas la suivre? –

+0

@David: C'est juste une question de goût personnel. La portée de la variable '@ output' est accessible dans le BEGIN, je garde simplement ma déclaration de variables hors du BEGIN pour être explicite sur ce qui se passe. –

+0

Merci Ponies, mais maintenant j'obtiens l'erreur 'Une expression de type non-booléen spécifié dans un contexte où une condition est attendue, près de 'lpi'.'. J'ai mis à jour mon premier message avec le code que vous avez suggéré, pouvez-vous voir ce qui ne va pas? – Mickel

0
SCALAR VALUED FUNCTION EXAMPLE BY RAJESH 

CREATE FUNCTION GETMYDATE(@YEAR INT) 
RETURNS DATETIME 
AS 
BEGIN 
    DECLARE @DATE DATETIME 
    IF @YEAR>2000 
     SET @DATE=GETDATE() 
    ELSE 
     SET @DATE=NULL 

    RETURN @DATE 
END