【问题标题】:Need help with Scalar-valued function in SQL Server 2008需要有关 SQL Server 2008 中标量值函数的帮助
【发布时间】:2010-12-30 08:21:41
【问题描述】:

我需要有关此标量值函数的帮助。

我想要做的是在max(Value) AS MaxValue这一行返回我在MaxValue中得到的值。

如果ItemIdListPropertyId 存在,该查询将只返回1 个值,但我无法创建它的函数。

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

【问题讨论】:

  • +1:对于使用表别名,但请不要在 SO 上发布制表符分隔的代码 - 它确实会干扰输出并使纠正它们变得很痛苦。有关降价语法的更多信息,请参阅:stackoverflow.com/editing-help

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


【解决方案1】:
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

【讨论】:

    【解决方案2】:

    将这些行添加到您的代码中,它应该可以工作:

    将此添加到开头(就在BEGIN之后)

    DECLARE @output int
    

    将此添加到末尾(就在 END 之前)

    RETURN @output
    

    像这样把它们放在一起:

    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
    

    【讨论】:

      【解决方案3】:

      我赞成你的问题,但我不喜欢任何答案。您应该将代码更改为内联表值函数。这段代码每次都会被认为是程序化的,它只是一个查询。

      我在http://msmvps.com/blogs/robfarley/archive/2009/12/05/dangers-of-begin-and-end.aspx 上写过,但我会很快解释你应该怎么做:

      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 
      );
      

      现在像这样使用它:

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

      如果您不想从数据集中删除行,可以使用 OUTER APPLY。您可以添加额外的聚合,如果您不引用它们将被完全忽略。但最重要的是,查询优化器会简化您的查询,因此如果它可以避免做大量工作,它就会这样做。

      希望这会有所帮助...

      【讨论】:

        【解决方案4】:

        用途:

        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
        

        SELECT @output = MAX(u.value) 将值分配给@output 变量,然后您需要使用RETURN 语法返回它。另一种方法是根据您的需要设置一个输出参数。

        我还将您的 JOIN 语法从 ANSI-89 转换为 ANSI-99。它的性能相当,但比旧语法更好地适应 LEFT JOIN,并且在其他数据库上得到广泛支持(如果需要,它更便于移植)。

        另外,试试:

          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
        

        我认为你不需要 CTE...

        【讨论】:

        • +1 不过,如果 BEGIN 是函数的那个​​,那么 @output 变量的声明不应该跟在它后面吗?
        • @David:这只是个人喜好问题。 @output 变量的范围可以在 BEGIN 中访问,我只是将变量声明保留在 BEGIN 之外,以便明确说明正在发生的事情。
        • 感谢小马,但现在我收到错误 An expression of non-boolean type specified in a context where a condition is expected, near 'lpi'.。我已经用你建议的代码更新了我的第一篇文章,你能看看有什么问题吗?
        • @Mickel:修复它 - 我在 LISTPROPERTYITEMS 加入中有 ON lpi lpi.id ...
        猜你喜欢
        • 1970-01-01
        • 2016-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多