结论:必须用create or alter view替代alter view和drop+create组合;创建视图须显式列名、两段式架构引用、避免非确定性函数;启用with schemabinding可防结构变更但限制基表修改。

直接说结论:用 CREATE VIEW 创建,用 CREATE OR ALTER VIEW 修改,别再用 ALTER VIEW —— 它不支持首次创建,且容易因权限或依赖问题失败。
创建视图必须避开的三个坑
很多人一上来就写 CREATE VIEW vw_xxx AS SELECT *,结果上线后出问题:
- 用
SELECT *会导致基表加列后视图查询突然多出字段,下游应用可能解析失败 - 没加架构名(如
dbo.vw_Students)时,SQL Server 默认用当前用户默认架构,不同登录用户执行可能指向不同视图 - 视图里用了函数(比如
GETDATE())、子查询或外部数据源(如链接服务器),就不能被索引视图引用,也影响某些工具的元数据识别
实操建议:
- 显式列出所有列,别偷懒用
* - 始终带上架构前缀:
CREATE VIEW dbo.vw_ActiveStudents AS ... - 如果视图要用于报表或 BI 工具,加个
WITH SCHEMABINDING(但注意:启用后基表不能删列、改类型,除非先删视图)
CREATE OR ALTER VIEW 是修改视图的唯一推荐方式
SQL Server 2016+ 引入的 CREATE OR ALTER VIEW 彻底替代了旧式组合(DROP VIEW + CREATE VIEW),也比 ALTER VIEW 更安全:
-
ALTER VIEW要求视图已存在,否则报错Msg 15151, Level 16, State 1: Cannot alter 'xxx' because it does not exist -
CREATE OR ALTER无论视图是否存在都执行成功,避免脚本在部署时因环境差异中断 - 它保留原有权限,而
DROP+CREATE会清空GRANT,导致应用查不到数据
示例:
CREATE OR ALTER VIEW dbo.vw_StudentCourses AS
SELECT
s.StudentID,
s.FirstName + ' ' + s.LastName AS FullName,
c.CourseName,
sc.EnrollmentDate
FROM dbo.Students s
INNER JOIN dbo.StudentCourses sc ON s.StudentID = sc.StudentID
INNER JOIN dbo.Courses c ON sc.CourseID = c.CourseID;
带选项的视图定义怎么加才不踩雷
常见选项有 WITH ENCRYPTION、SCHEMABINDING、VIEW_METADATA,但它们不是随便堆砌的:
-
WITH ENCRYPTION会加密视图定义(sys.sql_modules中内容不可读),但无法防止 DBA 用 DAC 连接提取,仅防普通用户查看;开启后,复制发布(Replication)会跳过该视图 -
WITH SCHEMABINDING要求所有引用对象用两段式名(schema.object),且基表不能删列、改列类型、删表——否则ALTER VIEW或CREATE OR ALTER VIEW直接失败 -
VIEW_METADATA主要影响 ODBC/JDBC 驱动的行为,让驱动把视图当成真实表返回元数据;一般不用加,除非对接老系统
如果你不确定要不要加,先不加。等真遇到权限控制或性能瓶颈再评估。
重命名视图和处理依赖关系的实际代价
别用 sp_rename 改视图名——它只改名字,不更新依赖链:
- 存储过程里写了
SELECT * FROM old_view,重命名后运行就报Invalid object name 'old_view' - SSMS 的“查看依赖关系”功能可能漏掉动态 SQL 或应用层硬编码的引用
- 即使你手动改了所有调用点,CI/CD 流水线里的旧脚本可能还在用原名
更稳妥的做法是:
- 新建一个同逻辑的视图(用新名),验证无误后,再逐步把应用切换过去
- 旧视图留着跑一段时间(比如 30 天),最后用
DROP VIEW old_name清理 - 用
sys.dm_exec_describe_first_result_set或第三方工具(如 ApexSQL Search)扫描整个数据库找硬编码引用
真正麻烦的从来不是写一行 CREATE VIEW,而是改完之后,发现三个存储过程、两个报表服务数据集、还有 Java 应用里的 DAO 层字符串全得同步更新。










