如何将派生列列表(table 和列别名)应用于 SQL 服务器中的 table 值函数调用

How to apply a derived column list (table and column aliases) to a table valued function call in SQL Server

我在 SQL 服务器中模拟 PostgreSQL 风格 generate_series() table 值函数:

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

现在我想使用派生列列表语法来重命名列以及 table,如下所示:

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

产生此错误的原因:

Msg 195, Level 15, State 15, Line 5
'generate_series' is not a recognized function name.

... 而此语法(限定函数)...

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

... 产生此错误:

Msg 317, Level 16, State 1, Line 5
Table-valued function 'generate_series' cannot have a column alias.

我认为这种语法完全有效。它在 PostgreSQL、标准 SQL 和 "ordinary" T-SQL 中也是这样工作的,例如:

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

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

我正在使用 SQL Server Express 2014

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

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

SELECT *
FROM
  TableName t(Col)

行不通

但是

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

会起作用

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

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

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

在这种情况下您不能添加列别名。这不是使用 table 值构造函数,而是从 table 值函数返回。只需删除列别名即可。

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

FWIW,我建议在您的函数中使用计数 table 而不是递归 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

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

column_alias 仅支持派生的 table 和 @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 调用。例如在派生的 table 或 CTE 中为列添加别名。