SQL 服务器 'AS' 别名意外的语法

SQL Server 'AS' alias unexpected syntax

我今天遇到了关注T-SQL的人:

select c from (select 1 union all select 1) as  d(c)

产生以下结果:

c
-----------
1
1

让我感到困惑的部分是 d(c)

在试图理解发生了什么时,我将 T-SQL 修改为:

select c, b from (select 1, 2 union all select 3, 4) m(c, b)

产生以下结果:

c           b
----------- -----------
1           2
3           4

很明显 d & m 是 table 引用,而括号 c & b 是对列的引用。 我没能在 msdn 上找到相关文档,但很好奇 if

  1. 你知道这样的语法吗?
  2. 什么是有用的用例场景?
select c from (select 1 union all select 1) as d(c)

相同
select c from (select 1 as c union all select 1) as d

在第一个查询中,您没有在子查询中命名列,而是在子查询之外命名它们,

在第二个查询中,您在子查询中命名列

如果您这样尝试(不命名子查询中的列)

select c from (select 1 union all select 1) as d

你会得到以下错误

No column name was specified for column 1 of 'd'

这也在Documentation

至于用法,有的喜欢写第一种方法,有的喜欢第二种方法,随便你怎么写。都一样

您已经有评论指出派生的 table 是如何工作的文档,但不是为了回答您有关此功能的有用用例的问题。

就我个人而言,每当我想创建一组将在您的语句中广泛使用的可寻址值时,或者当我出于任何原因想要复制行时,我都发现此功能很有用。

可寻址值的一个例子是以下更复杂的版本,其中 v 派生的 table 中的计算值可以通过更合理的名称多次使用,而不是难以理解的重复计算:

select p.ProductName
      ,p.PackPricePlusVAT - v.PackCost as GrossRevenue
      ,etc
from dbo.Products as p
    cross apply(values(p.UnitsPerPack * p.UnitCost
                      ,p.UnitPrice * p.UnitsPerPack * 1.2
                      ,etc
                      )
               ) as v(PackCost
                     ,PackPricePlusVAT
                     ,etc
                     )

能够复制行的一个例子是创建一个用于验证数据的异常报告,它将为 dbo.Product 行满足的每个 DataError 条件输出一行:

select p.ProductName
      ,e.DataError
from dbo.Products as p
    cross apply(values('Missing Units Per Pack'
                      ,case when p.SoldInPacks = 1 and isnull(p.UnitsPerPack,0) < 1 then 1 end
                      )
                     ,('Unusual Price'
                      ,case when p.Price > (p.UnitsPerPack * p.UnitCost) * 2 then 1 end
                      )
                     ,(etc)
               ) as e(DataError
                     ,ErrorFlag
                     )
where e.ErrorFlag = 1

如果您能理解这两个脚本的作用,您应该会找到大量示例,说明在哪些地方能够生成额外的值或额外的数据行会非常有帮助。

观察:使用 table 构造函数 values 无法命名列,这使得必须在 table 别名之后使用列命名:

select * from
(values
     (1,2) -- can't give a column name here
    ,(3,4)
) as tableName(column1,column2) -- gotta do it here