0

我正在尝试创建一个存储的 sql server 函数,该函数将返回一个中值表,我可以将其连接回另一个表,因此:

CREATE FUNCTION [dbo].getmedian (@varPartionBy1 int,@varPartionBy2 int, @varForTieBreak int, @varForMeasure int)
    RETURNS TABLE
    AS
    RETURN 
    (
        SELECT
           @varPartionBy1,
           @varPartionBy2,
           AVG(@varForMeasure) 
        FROM
        (
           SELECT
              @varPartionBy1,
              @varPartionBy2,
              ROW_NUMBER() OVER (
                 PARTITION BY @varPartionBy1, @varPartionBy2
                 ORDER BY @varForMeasure ASC, @varForTieBreak ASC) AS RowAsc,
              ROW_NUMBER() OVER (
                 PARTITION BY @varPartionBy1, @varPartionBy2 
                 ORDER BY @varForMeasure ASC, @varForTieBreak  DESC) AS RowDesc
            from 
            [fakename].[dbo].[temptable] bp

        ) bp
        WHERE 
           RowAsc IN (RowDesc, RowDesc - 1, RowDesc + 1)
        GROUP BY @varPartionBy1, @varPartionBy2

    )

这将返回错误:“消息 8155,级别 16,状态 2,过程 getmedian,第 25 行没有为 'bp' 的列 1 指定列名。” -- 表示我不明白如何在 UDF 的上下文中为列分配表别名,我猜。

我应该怎么做才能修复错误?

这是我的第一个 USF,因此我感谢您在解决主要问题时提供的任何其他有用的设计见解。谢谢你的帮助!

4

2 回答 2

2

SELECT @varPartionBy1, @varPartionBy2需要为它们分配列名的地方。您可以直接分配它们,例如,SELECT @varPartionBy1 AS varPartionBy1或者SELECT varPartionBy1 = @varPartionBy1您可以在表别名中指定它) bp(varPartionBy1, varPartionBy2,...

正确的功能可能是

CREATE FUNCTION [dbo].getmedian (@varPartionBy1 int,@varPartionBy2 int, @varForTieBreak int, @varForMeasure int)
RETURNS TABLE
AS
RETURN 
(
    SELECT
       varPartionBy1,
       varPartionBy2,
       AVG(@varForMeasure) AS AvgVarForMeasure
    FROM
    (
       SELECT
          @varPartionBy1 AS varPartionBy1,
          @varPartionBy2 As varPartionBy1,
          ROW_NUMBER() OVER (
             PARTITION BY @varPartionBy1, @varPartionBy2
             ORDER BY @varForMeasure ASC, @varForTieBreak ASC) AS RowAsc,
          ROW_NUMBER() OVER (
             PARTITION BY @varPartionBy1, @varPartionBy2 
             ORDER BY @varForMeasure ASC, @varForTieBreak  DESC) AS RowDesc
        from 
        [fakename].[dbo].[temptable] bp

    ) bp
    WHERE 
       RowAsc IN (RowDesc, RowDesc - 1, RowDesc + 1)
    GROUP BY varPartionBy1, varPartionBy2

)
于 2013-11-27T20:04:56.073 回答
1

好吧,一旦你解决了语法问题,你的问题就不会结束。一方面,你不能真正做你想做的事情(将变量传递给PARTITION BYandORDER BY子句)。这些只是被视为常量,因此ROW_NUMBER()将任意应用。

观察这里发生的事情:

DECLARE @foo SYSNAME = N'name';

SELECT name, foo = @foo, -- this is just a constant value, not a column
  varASC  = ROW_NUMBER() OVER (ORDER BY @foo ASC), 
  varDESC = ROW_NUMBER() OVER (ORDER BY @foo DESC), 
  colASC  = ROW_NUMBER() OVER (ORDER BY name ASC), 
  colDESC = ROW_NUMBER() OVER (ORDER BY name DESC) 
FROM sys.objects --WHERE is_ms_shipped = 0
ORDER BY varASC;

部分结果:

name  foo   varASC  varDESC  colASC  colDESC
----  ----  ------  -------  ------  -------
t1    name       1        1       1      100
t2    name       2        2       2       99
t3    name       3        3       3       98
t4    name       4        4       4       97
t5    name       5        5       5       96
------ only column that deviates ----^^^^^^^

每一行的变量值@foo都是相同的,因此,按它进行分区和排序是完全没有意义的。

于 2013-11-27T20:12:03.997 回答