在Sproc中多次使用UDF

时间:2013-11-20 21:10:00

标签: tsql sql-server-2005 user-defined-functions

我正在使用SQL 2k5 sproc。

我需要引用UDF来根据一些变量和用户权限来计算价格。我最初尝试过这个,但它没有用,因为我没有引用一个字段......

SELECT dbo.f_GetPrice(model,userid,authType) 'YourPrice', name, description 
FROM tblRL_Products
WHERE 'YourPrice' Between @fromPrice AND @toPrice
     OR 'YourPrice' IS NULL

所以我将其修改为

SELECT dbo.f_GetPrice(model,userid,authType) 'YourPrice', name, description 
FROM tblRL_Products
WHERE dbo.f_GetPrice(model,userid,authType) Between @fromPrice AND @toPrice
     OR dbo.f_GetPrice(model,userid,authType) IS NULL

当SQL执行此sproc时,它是为每条记录运行3X的函数还是一次运行它并使用每行其他两个位置的值。

有更有效的方法吗?


修改

这是Scalar UDF。它需要根据用户授权的类型获取价格,然后一旦我们有合适的价格,我们就需要对其进行计算。这全部存储在授权表中。每个用户都拥有每个产品系列的授权。因此,他们可能为每一行提供不同的价格类型和计算,在一次搜索结果调用中返回数十行甚至数百行。

在上面的代码中,我使用了authType,这是一个旧的调用,我们不再使用该参数了。

ALTER function [dbo].[f_GetPrice]
(
    @model uniqueidentifier,
    @userID uniqueidentifier    
)
returns money
as
begin

Declare @yourPrice money

WITH ProductPrice AS(
SELECT (CASE PriceType
        WHEN 'msrp' THEN p.price_msrp
            WHEN 'jobber' THEN p.price_jobber
            WHEN 'warehouse' THEN p.price_warehouse
            WHEN 'margin' THEN p.price_margin
            WHEN 'mycost' THEN p.price_mycost
            WHEN 'customprice1' THEN p.price_custom1
            WHEN 'customprice2' THEN p.price_custom2
            WHEN 'customprice3' THEN p.price_custom2
            ELSE p.price_msrp
        END) as YourPrice, aup.calc, aup.amount
FROM products p 
    JOIN lines l ON l.lineID=l.lineID
    JOIN authorizations a ON l.authlineID=a.authlineID
    JOIN authorizationusers au ON a.auID=au.auID
    JOIN authorizationuserprices aup ON au.aupID=aup.aupID
WHERE au.userID=@userID AND p.modelID=@model)


SELECT @yourPrice=(CASE calc
            WHEN 'amount' THEN YourPrice+amount
            WHEN 'percent' THEN YourPrice+(YourPrice*amount/100)
            WHEN 'divide' THEN YourPrice/amount
            WHEN 'factore' THEN YourPrice*amount
            WHEN 'none' THEN YourPrice
            ELSE YourPrice
           END) FROM ProductPrice

return @yourPrice

END

2 个答案:

答案 0 :(得分:5)

如果必须使用udf,则使用子查询并在子查询外部进行过滤:

select YourPrice, name, description
from
(
  SELECT dbo.f_GetPrice(model,userid,authType) YourPrice, name, description 
  FROM tblRL_Products
) d
WHERE YourPrice Between @fromPrice AND @toPrice
     OR YourPrice IS NULL

然后你只调用你的udf而不是3次。

答案 1 :(得分:0)

当标量函数必须应用于相当多的行时,标量函数并不好。在这种情况下,您肯定可以将标量函数转换为表值函数,对于每一行输入数据都不会调用一次。

create function [dbo].[ft_GetPrice]
(
    @model uniqueidentifier,
    @userID uniqueidentifier    
)
returns table
as return
(
    WITH ProductPrice AS (
        SELECT (CASE PriceType
                WHEN 'msrp' THEN p.price_msrp
                    WHEN 'jobber' THEN p.price_jobber
                    WHEN 'warehouse' THEN p.price_warehouse
                    WHEN 'margin' THEN p.price_margin
                    WHEN 'mycost' THEN p.price_mycost
                    WHEN 'customprice1' THEN p.price_custom1
                    WHEN 'customprice2' THEN p.price_custom2
                    WHEN 'customprice3' THEN p.price_custom2
                    ELSE p.price_msrp
                END) as YourPrice, aup.calc, aup.amount
        FROM products p 
            JOIN lines l ON l.lineID=l.lineID
            JOIN authorizations a ON l.authlineID=a.authlineID
            JOIN authorizationusers au ON a.auID=au.auID
            JOIN authorizationuserprices aup ON au.aupID=aup.aupID
        WHERE au.userID=@userID AND p.modelID=@model
    )
    SELECT
        CASE calc
            WHEN 'amount' THEN YourPrice+amount
            WHEN 'percent' THEN YourPrice+(YourPrice*amount/100)
            WHEN 'divide' THEN YourPrice/amount
            WHEN 'factore' THEN YourPrice*amount
            WHEN 'none' THEN YourPrice
            ELSE YourPrice
        END as YourPrice
    FROM ProductPrice
)
GO

然后可以用作:

SELECT fp.YourPrice, name, description
FROM tblRL_Products
    outer apply dbo.ft_GetPrice(model, userid, authType) fp
WHERE fp.YourPrice Between @fromPrice AND @toPrice OR fp.YourPrice IS NULL