【问题标题】:How to apply a derived column list (table and column aliases) to a table valued function call in SQL Server如何将派生列列表(表和列别名)应用于 SQL Server 中的表值函数调用
【发布时间】:2017-04-17 13:52:31
【问题描述】:

我在 SQL Server 中模拟 PostgreSQL 风格的 generate_series() 表值函数:

CREATE FUNCTION generate_series(@d1 DATE, @d2 DATE)
RETURNS TABLE AS
RETURN
  -- Ignore implementation (returning a single DATE column) for this question

现在可以按预期使用:

SELECT *
FROM generate_series(
  CAST ('2005-07-01' AS DATE),
  CAST ('2005-07-31' AS DATE)
) t

现在我想使用派生列列表语法来重命名列以及表:

SELECT *
FROM generate_series(
  CAST ('2005-07-01' AS DATE),
  CAST ('2005-07-31' AS DATE)
) t(col)

产生此错误的原因:

消息 195,第 15 级,状态 15,第 5 行
“generate_series”不是可识别的函数名称。

... 而这种语法(限定函数)...

SELECT *
FROM dbo.generate_series(
  CAST ('2005-07-01' AS DATE),
  CAST ('2005-07-31' AS DATE)
) t(col)

...正在产生此错误:

消息 317,第 16 级,状态 1,第 5 行
表值函数“generate_series”不能有列别名。

在我看来,这种语法是完全有效的。它在 PostgreSQL、标准 SQL 和“普通”T-SQL 中也是如此,例如:

SELECT *
FROM (
  VALUES (1),(2)
) t(col)

我做错了什么?我怎么能做到这一点? (I'm aware of the possibility of emulating this,但我想真正使用派生列列表语法)。

我使用的是 SQL Server Express 2014

【问题讨论】:

  • 你需要架构/函数所有者。默认为dbo 因此将给出FROM dbo.generate_series
  • @MatBailie:呃。好的谢谢。但这还不能解决问题。会更新。
  • 鉴于错误消息 317 的性质,我们应该说,这似乎很奇怪,具体,我不希望找到一种方法来直接将列别名应用于一个表值函数。
  • 语法在这里msdn.microsoft.com/en-us/library/ms177634.aspxcolumn_alias 只能在少数情况下使用。不包括user_defined_function
  • @MartinSmith:谢谢,如果你想这么说,那将是理想的答案。有趣的是,@variable.function_call... 允许使用列别名

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


【解决方案1】:
SELECT *
FROM
    (
       SELECT *
       FROM dbo.generate_series(
        CAST ('2005-07-01' AS DATE),
        CAST ('2005-07-31' AS DATE)
    )) t(col)

我猜这是因为虽然 dbo.generate_series 是一个函数,但它正在返回一个表。所以:

SELECT *
FROM
  TableName t(Col)

没用

但是

SELECT *
FROM
(
   SELECT *
   FROM
     TableName t
) t(col)

会有用的

换句话说,派生列列表将与派生表一起使用,但当表不是派生时则不行?

我会假设你知道的首选语法是使用列别名而不是派生列列表。

SELECT d as Col
FROM
    dbo.generate_series(
        CAST ('2005-07-01' AS DATE),
        CAST ('2005-07-31' AS DATE)
    ) t

【讨论】:

  • 确实,还有其他解决方法,如 the article I've linked 中所述,包括 CTE、带有虚拟第一个子查询的 UNION...
  • @LukasEder 我认为 Sean 的观点是该函数是一个表而不是派生表,因此您不能使用派生列列表。但我承认我不会过多地使用派生列列表,因此我不会认为自己是该主题的实际代表。
  • 有趣的是,我不认为 SQL Server 使用标准术语“派生列列表”,但我想这仍然是最好的解释(并且 PostgreSQL 改变了标准以使其在更广泛的上下文中工作)。您的第一个示例确实是最接近 SQL Server 的解决方法
【解决方案2】:

在这种情况下,您无法添加列别名。这不是使用表值构造函数,而是从表值函数返回。只需删除列别名就可以了。

SELECT *
FROM dbo.generate_series(
  CAST ('2005-07-01' AS DATE),
  CAST ('2005-07-31' AS DATE)
) t

FWIW,我建议在您的函数中使用计数表而不是递归 cte。如果您的日期范围很长,则性能会受到影响,因为您实际上是在使用 rcte 进行计数。如果您检查执行计划,则它与 while 循环相同。 Jeff Moden 有一篇很棒的文章详细讨论了这个问题。 http://www.sqlservercentral.com/articles/T-SQL/74118/

--编辑--

要创建别名,你不能简单地添加一个别名吗?

SELECT t.d as MyAlias
FROM dbo.generate_series(
  CAST ('2005-07-01' AS DATE),
  CAST ('2005-07-31' AS DATE)
) t

【讨论】:

  • 谢谢,但你并没有真正回答我的问题 :) 1) 性能是题外话(我会更新我的问题),2) 语法是这里的重要部分(至少对我来说)
  • 1) 性能永远不应偏离主题。 2)我确实回答了你的问题。如果您想为该列设置别名,只需在选择中添加一个别名,就像对任何其他查询一样。
  • 1) 如果您坚持,可以:)。但这在我的问题的背景下是噪音,所以让我用评论替换实现(消除我自己的噪音)。 2) SELECT 别名通常不起作用,因为该名称不适用于所有其他子句(例如 WHERE)。
  • 1) 这就是为什么它在我的帖子末尾。而且大多数人没有意识到计数 cte 的性能有多可怕。 :) 2) 确实,您不能在 where 子句中使用它,但您的问题(至少对我而言)并不清楚您是否需要它。您将不得不使用马特发布的 cte 或子查询。
【解决方案3】:

from 子句的相关部分在这里。

column_alias 仅支持派生表和@variable.function_call

[ FROM { <table_source> } [ ,...n ] ]   
<table_source> ::=   
{  
    table_or_view_name [ [ AS ] table_alias ]   
        [ <tablesample_clause> ]   
        [ WITH ( < table_hint > [ [ , ]...n ] ) ]   
    | rowset_function [ [ AS ] table_alias ]   
        [ ( bulk_column_alias [ ,...n ] ) ]   
    | user_defined_function [ [ AS ] table_alias ]  
    | OPENXML <openxml_clause>   
    | derived_table [ [ AS ] table_alias ] [ ( column_alias [ ,...n ] ) ]   
    | <joined_table>   
    | <pivoted_table>   
    | <unpivoted_table>  
    | @variable [ [ AS ] table_alias ]  
    | @variable.function_call ( expression [ ,...n ] )   
        [ [ AS ] table_alias ] [ (column_alias [ ,...n ] ) ]  
    | FOR SYSTEM_TIME <system_time>   
}  

因此,至少目前,您需要封装user_defined_function 调用。例如在派生表或 CTE 中为列设置别名。

【讨论】:

    猜你喜欢
    • 2015-08-25
    • 2022-08-14
    • 2018-06-29
    • 1970-01-01
    • 2021-07-28
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多