如何将派生列列表(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 中为列添加别名。
我在 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 中为列添加别名。