SQL Server UDF 的列别名错误

Posted

技术标签:

【中文标题】SQL Server UDF 的列别名错误【英文标题】:Column alias error with SQL Server UDF 【发布时间】:2013-11-27 19:57:29 【问题描述】:

我正在尝试创建一个存储的 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,因此我感谢您在解决主要问题时提供的任何其他有用的设计见解。感谢您的帮助!

【问题讨论】:

在内部选择中,为变量提供别名@varPartionBy1 as varPartionBy1,然后在外部选择中调用新别名而不是变量。 我建议您创建一个问题,显示临时表中的一些示例数据,然后显示您对给定参数值的期望结果。在这里,我无法从代码中推断出它真正应该做什么。 【参考方案1】:

您有SELECT @varPartionBy1, @varPartionBy2 的地方需要为它们分配列名。您可以直接分配它们,例如SELECT @varPartionBy1 AS varPartionBy1SELECT 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

)

【讨论】:

谢谢!我想根据 Aaron Bertrand 的评论,这个决议不会解决我所有的问题,但至少我已经知道了这个问题的答案。【参考方案2】:

好吧,一旦你解决了语法问题,你的问题就不会结束。一方面,你不能真正做你想做的事(将变量传递给PARTITION BYORDER 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 的变量值在每一行上都是相同的,因此,按此划分和排序完全没有意义。

【讨论】:

去使用动态sql吗? @CRAFTYDBA 在函数中?我不这么认为。 我的错,我以为这是一个 SP。但是具有动态 SQL 的 SP 可能是一个解决方案。业务需求不足,无法做出判断。 谢谢亚伦。我要做的就是将由某个组按变量划分的中值获取到更大的选择语句的结果中。有没有可以推荐的解决方案?我已经尝试了多种方法,但我有点喜欢 UDF,因为它总体上看起来更灵活,并且对核心 select 语句不太麻烦。 正如我在上面的评论中所建议的,您应该发布一个具有明确要求的问题,包括示例数据、提供的参数和所需的结果。上面的代码不可能完成它听起来像你想要的,但即使有你想要的附加描述,我也不明白“由某些变量组分区”是什么意思,如果我不知道是什么单词问题意味着我当然不能建议代码来解决它。

以上是关于SQL Server UDF 的列别名错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Access SQL 的列别名中使用表名?

sql server 基础语法2

SQL server 种JOIN后的语句无法别名

Java中的Pig UDF:错误---错误1066:无法打开别名的迭代器

在 SQL 视图中的列选择中使用左连接别名

SELECT 语句中的列别名不适用于 SQuirrel SQL + Firebird