SQL Server索引视图禁止SELECT *,因其违反SCHEMABINDING要求、导致列映射不唯一、执行计划不稳定,且ANSI标准强制列名须静态可析出;必须显式指定每列并带唯一别名。

因为 SQL Server 索引视图(以及很多企业级场景)根本**不接受 * 或 table.* 语法**——这不是风格问题,是硬性语法拦截。
CREATE VIEW 报 “列名不明确” 或 “无法绑定架构” 的真实原因
错误常被误读为权限或命名问题,实际触发点往往是列定义模糊。SQL Server 要求索引视图的列必须可唯一、确定地映射到基表列或表达式结果,而 * 会掩盖列来源、顺序、空值性、数据类型推导等关键信息。
-
*在基表结构变更后行为不可控:比如新增一列,SELECT *视图的列序和语义就变了,物化索引无法保证一致性 -
table.*无法满足 SCHEMABINDING 要求:绑定需精确到每个列的归属,dbo.Orders.*不算“显式列名”,会被拒绝 - 查询优化器无法为
*视图生成稳定执行计划:缺少列元数据,无法做确定性谓词推导或索引匹配
哪些写法算“显式指定列名”?
核心是:每一列都必须有明确、唯一的名称,且不能依赖通配符展开。
- ✅ 正确:
SELECT o.OrderID, o.OrderDate, c.CustomerName AS Customer - ✅ 允许别名:
COUNT(*) AS TotalCount,但必须带AS或空格分隔 - ❌ 错误:
SELECT * FROM dbo.Orders - ❌ 错误:
SELECT dbo.Orders.* FROM dbo.Orders - ❌ 错误:
SELECT OrderID, OrderDate, (SELECT TOP 1 Name FROM dbo.Customers) FROM dbo.Orders—— 子查询无别名,列名不合法
为什么 ANSI 标准要求这样?
ANSI SQL-92 及后续标准规定:视图的列名必须在定义时静态可析出,不能依赖运行时元数据。这是为了确保跨平台可移植性与逻辑确定性。
- SQL Server 严格遵循该原则,尤其在启用
SCHEMABINDING后,会逐列校验是否属于某张基表、是否可 null、是否为计算列 - PostgreSQL、Oracle 同样禁止
*用于可物化视图;MySQL 虽允许,但在创建 MERGE 可算法视图时也会报错 - 如果用 SSMS 图形设计器生成视图,默认可能插
*,务必手动改掉并验证sys.dm_exec_describe_first_result_set(N'your view definition')返回的列名是否全非 NULL
最容易被忽略的是:哪怕你只差一个别名,比如 COUNT(*) Total(缺 AS),SQL Server 也会认为列名未显式声明——它要求语法上必须存在标识符,而不是靠解析器推测。

















