尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

SQL自学:视图创建语法、权限与性能优化实战指南

发布时间:2026/9/26 12:26:07

资讯中心
01
ARTICLE

SQL自学:视图创建语法、权限与性能优化实战指南

SQL自学:视图创建语法、权限与性能优化实战指南
SQL 入门阶段十个人里总有八个会在“视图”这个概念上绕一下。我第一次在同事代码里看到CREATE VIEW的时候还以为他是建了一张临时表后来发现数据对不上才老老实实回头翻定义。这篇就围绕“SQL 自学怎么创建视图”来写把视图的语法、实操、权限、性能踩坑一次讲清楚。看完之后你至少能在 SQL Server 2022 或 2019 环境下用 T-SQL 和 SSMS 轻松创建出自己想要的视图也知道遇到“创建视图权限不足”或者视图查询变慢时该从哪里排查。1. 先把“视图是什么”说透再来谈怎么创建1.1 视图不是表而是一段“存起来的查询”很多人刚学 SQL 时容易把视图当成一张“能看到数据的表”。本质不是这样。视图本身不保存数据它保存的是一条SELECT查询语句。当你执行SELECT * FROM v_视图名时数据库引擎会把视图名字替换成视图里定义的那段子查询然后重新执行一次。我习惯用一个类比来解释视图就像 Windows 桌面上的快捷方式。快捷方式本身不是程序双击它才会打开对应软件视图本身不装数据查询它时才会去底层表里现取数据。所以视图里的数据永远跟着基础表走基础表数据变了视图查出来的结果跟着变。也正因为这一点后端报表、前端看板才会那么喜欢用视图——查同一个视图谁都能拿到当前最新状态不用反复粘贴同一段 SQL。学习视图的困难多半来自这里你明明创建了一个名字像表的东西但它没有自己的存储空间也不能像表那样随便加索引普通视图不行。记住这条主线后面所有细节都顺了。1.2 视图到底解决什么问题我整理了一下实际项目里最常见的四个使用场景每个场景都对应一类需求创建视图时心里要有数。第一是实现“统一口径”。业务部门要统计订单金额时有人算含税有人算不含税有人把退款单也算进去了。这时候建一个v_order_amount_standard视图把过滤条件、公式一次性定死开发人员只查这个视图口径就统一了。第二是隐藏敏感字段。用户表可能包含密码、身份证号、内部备注直接给外部系统开整表权限风险太大。这时创建一个视图只暴露姓名、部门、工号这些必要字段再把视图的查询权限授出去底层表的访问权限仍然收紧。第三是简化高频复杂查询。多表JOIN、多层子查询、聚合报表这些 SQL 又长又容易拼错。建个视图把复杂度封装起来业务层每次只需要SELECT * FROM v_xxx WHERE ...就好。这也是为什么网上很多 SQL 复习资料里一定会出现 CREATE VIEW 练习题。第四是兼容表结构变更。老系统改名了、字段拆分了但外部接口还在用旧字段名可以在旧接口层建个视图把新结构映射成老结构避免一大批代码重写。这种场景在升级遗留系统时特别实用。1.3 创建视图前必须先想清楚的几件事我建议你在写CREATE VIEW之前先回答三个问题这个视图给谁用它依赖的表和字段稳定吗查询语句能不能做到只取必要字段给谁用决定了你要不要加权限控制、要不要过滤掉敏感列。依赖的表稳定程度决定了要不要加SCHEMABINDING因为一旦用了模式绑定底层表结构改动就会受到限制好处是视图定义不容易因为字段被改而悄悄烂掉。只取必要字段则能避免“SELECT *写进视图后面表加了列导致视图结果集和业务代码不匹配”这种经典事故。别小看这些问题。很多人创建视图失败不是因为语法不会写而是因为没想清楚视图要在什么边界内生存。我自己带新人时就强调视图是给你解决查询问题的不是给你制造“又一个数据源”的。能一条 SQL 解决就别急着封装确实要复用的查询才值得建视图。2. 创建视图的语法拆解与设计要点2.1 最小可用的 CREATE VIEW 语句T-SQL 里创建视图的语法非常短CREATE VIEW 视图名 AS SELECT 列1, 列2, ... FROM 表名 WHERE 条件;如果你想显式指定列名可以在视图名后面加个括号列表CREATE VIEW v_employee_brief (emp_no, emp_name, dept_name) AS SELECT e.emp_no, e.emp_name, d.dept_name FROM dbo.employee e JOIN dbo.department d ON e.dept_id d.dept_id;注意视图名字前面最好带上 schema比如dbo.v_employee_brief。没有写 schema 时会默认取当前用户的默认 schema容易在不同环境里出现解析差异。我见过两个测试环境执行同样代码一个建在dbo一个建在guest用户自己的 schema 里后面排查了半天就是因为视图建错了位置。视图里的SELECT基本可以用所有查询语法JOIN、GROUP BY、HAVING、CASE WHEN、LEFT JOIN都可以。但默认情况下视图内不能用ORDER BY除非你在ORDER BY前面加了TOP、OFFSET或FOR XML之类的子句。因为视图是关系对象理论上行序不该有固定意义排序应该在外部查询里做-- 这样会报错除非另外还指定了 TOP、OFFSET 或 FOR XML否则ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。 CREATE VIEW v_order_list AS SELECT * FROM dbo.orders ORDER BY order_date DESC; -- 错误示范 -- 正确的做法 CREATE VIEW v_order_list AS SELECT TOP (1000) * FROM dbo.orders ORDER BY order_date DESC; -- TOP 存在时允许日常查询视图时你在外部加上ORDER BY就好。这一条几乎新手必踩。2.2 常用选项ENCRYPTION、SCHEMABINDING、WITH CHECK OPTION除了上面基础语法SQL Server 还支持几个创建视图时直接写在语句里的选项每个选项背后都有明确的使用目的。WITH ENCRYPTION会在系统目录里混淆视图定义文本避免别人用sp_helptext或 SSMS 直接看到你写的 SQL。适合封装一些含算法、敏感业务规则的对象。但副作用也很明显一旦连你自己都看不到定义后续维护就完全依赖脚本备份。我强烈建议如果加密视图一定要把源代码脚本同步放到版本库里。CREATE VIEW v_salary_stat (dept_id, avg_salary) WITH ENCRYPTION AS SELECT dept_id, AVG(salary) FROM dbo.employee_salary GROUP BY dept_id;WITH SCHEMABINDING则是模式绑定它要求视图中引用的对象都用“两段式名称”dbo.employee_salary这样带 schema 的写法。启用以后底层表不能直接删除也不能随意修改视图引用的列。好处是视图定义稳固索引视图也必须带这个选项。坏处是改表时得多一步先把视图删掉或修改否则表结构改动会失败。WITH CHECK OPTION要在可更新视图上使用。它强制所有通过视图写入的数据都必须满足视图里的WHERE条件。举个最简单的例子视图v_order_valid只查有效订单status 有效如果直接往这个视图插入一条status 作废的记录没有CHECK OPTION时可能插入成功但插入后数据却从视图里“消失”查不到容易造成混乱加上WITH CHECK OPTION后数据库会直接拒绝这条不符合视图条件的数据写入。CREATE VIEW v_order_valid AS SELECT order_id, order_amount, status FROM dbo.orders WHERE status 有效 WITH CHECK OPTION;很多资料把这几个选项分开讲实际项目里更常组合使用。比如做报表层视图我一般会加SCHEMABINDING因为基础表都是受控的表结构给外部系统暴露数据时则更常用WITH ENCRYPTION保护字段逻辑。2.3 别把视图做成“能更新的万能表”视图能不能插入和更新是程序员最爱问的问题之一。简单回答单表、包含基础表主键、没做聚合运算的视图大多数情况下是可更新的。你甚至可以直接对视图INSERT和UPDATE数据库会把操作映射到基础表上去。但一旦视图里出现了JOIN、GROUP BY、DISTINCT、聚合函数可更新性就会变得复杂。不加处理地往多表关联视图里插数据SQL Server 会报“视图或函数不可更新因为修改会影响多个基表”之类的错误。这时候有三个选择一是改业务逻辑直接更新基础表二是对视图创建INSTEAD OF触发器在里面自己写清楚插入、更新、删除逻辑三是慎用可更新视图把它当成“只读报表”使用就好。我的看法是别把视图当成万能表。视图最稳的用法是查询写入操作尽量走明确的INSERT/UPDATE语句这样执行计划、权限控制、日志审计都清晰。你要是把大量可更新视图摊开给业务方后面一旦有人插入了一条违反业务规则的数据排查成本会高到让你怀疑人生。3. 实操从零创建一个可用的 SQL 视图3.1 准备演示表员工表和订单表纸上谈兵没意思直接实操。这里我用 SQL Server 2019/2022 语法在 SSMS 里新建一个查询窗口依次执行建表脚本。演示场景是员工表、部门表再建了一张销售订单表最终生成一个“销售订单明细视图”。CREATE TABLE dbo.department ( dept_id INT PRIMARY KEY, dept_name NVARCHAR(50) NOT NULL ); CREATE TABLE dbo.employee ( emp_no INT PRIMARY KEY, emp_name NVARCHAR(50) NOT NULL, dept_id INT NOT NULL, salary DECIMAL(10, 2), hire_date DATE ); CREATE TABLE dbo.sales_order ( order_id INT PRIMARY KEY, emp_no INT NOT NULL, customer_name NVARCHAR(50), order_date DATE, order_amount DECIMAL(12, 2), status NVARCHAR(20) );插入一些测试数据INSERT INTO dbo.department(dept_id, dept_name) VALUES (1, N技术部), (2, N市场部), (3, N销售部); INSERT INTO dbo.employee(emp_no, emp_name, dept_id, salary, hire_date) VALUES (1001, N张三, 1, 20000, 2021-03-01), (1002, N李四, 2, 15000, 2022-05-10), (1003, N王五, 3, 18000, 2020-01-15), (1004, N赵六, 3, 12000, 2023-07-01); INSERT INTO dbo.sales_order(order_id, emp_no, customer_name, order_date, order_amount, status) VALUES (5001, 1001, N客户A, 2024-01-10, 1200.00, N有效), (5002, 1003, N客户B, 2024-01-11, 2300.50, N有效), (5003, 1003, N客户C, 2024-01-12, 500.00, N作废), (5004, 1004, N客户D, 2024-01-15, 8000.00, N有效);建表和插入数据都要在同一个数据库里执行建议选一个测试库不要动生产数据。3.2 用 T-SQL 创建第一个多表关联视图现在需求来了报表组需要一张“员工销售明细表”里面要有订单号、客户、金额、状态还要带上员工姓名和部门名称。最笨的做法是每次写一遍三表JOIN很烦所以我们把它做成视图CREATE VIEW v_sales_order_detail AS SELECT so.order_id, so.order_date, so.customer_name, so.order_amount, so.status, e.emp_no, e.emp_name, d.dept_name, d.dept_id FROM dbo.sales_order so JOIN dbo.employee e ON so.emp_no e.emp_no JOIN dbo.department d ON e.dept_id d.dept_id;这段代码执行成功后SSMS 左侧的“视图”文件夹展开就能看到v_sales_order_detail。马上验证SELECT * FROM v_sales_order_detail;你会看到 4 条订单数据。注意5003那条虽然状态是作废但因为我们没在视图里写过滤条件它也正常显示出来了。如果业务上只需要有效订单可以在创建视图的时候加上WHERE status 有效或者做报表时在外部查询过滤。每当有人问我“创建视图和写普通 SELECT 有什么区别”时我会说区别就在“复用”。上面这个视图建完之后你想按部门汇总金额可以直接SELECT dept_name, SUM(order_amount) AS total_amount FROM v_sales_order_detail WHERE status 有效 GROUP BY dept_name;不用再关心三张表的关联细节。3.3 通过 SSMS 图形界面创建视图除了写 T-SQLSSMS 也提供了可视化创建视图的方式适合刚接触 SQL、对表结构不够熟的初学者。操作路径是在对象资源管理器里找到目标数据库展开“视图”右键点击“新建视图”。会弹出“添加表”窗口勾选你需要用到的表选择“添加”。然后可以在图形化区域里勾选列、设置表之间的JOIN关系、配置条件底层会自动生成对应的SELECT语句。编辑完点击运行确认数据没问题再按 CtrlS 保存输入视图名字即可。这个界面有个好处是能实时看到JOIN关系图对理解多表关联非常有帮助。但你也要知道它生成的 SQL 有时候比较“啰嗦”因为会带上括号和默认别名。等你有经验之后还是建议直接手写 T-SQL可控性高很多。另外提醒一点SSMS 图形界面创建的视图默认保存在你当前连接的数据库里。如果你在多人共用的服务器上做练习建出来的视图可能别人也能看到命名最好加上自己标识避免覆盖别人的同名视图。3.4 视图建好后怎么验证和查看定义视图创建成功后不能只看“命令已完成”就结束。建议做三件事验证字段、查看定义、测试权限。验证字段可以执行SELECT * FROM sys.columns WHERE object_id OBJECT_ID(dbo.v_sales_order_detail);或者用sp_helpEXEC sp_help dbo.v_sales_order_detail;它会列出视图的列清单、类型、是否可空等信息方便你和业务文档对照。查看定义则用EXEC sp_helptext dbo.v_sales_order_detail;如果当初创建时加了WITH ENCRYPTION这个存储过程看不清原码。这也是为什么加密视图要格外注意脚本备份。3.5 创建视图写脚本前的一个小习惯我个人建视图时会先写一段IF OBJECT_ID判断避免重复执行时报“数据库中已存在名为...”的错误IF OBJECT_ID(dbo.v_sales_order_detail, V) IS NOT NULL DROP VIEW dbo.v_sales_order_detail; GO CREATE VIEW dbo.v_sales_order_detail AS ...不过要注意直接DROP VIEW再CREATE VIEW会丢掉已经授予视图的权限所以更推荐在已有对象上使用ALTER VIEW。后面专门聊这个坑。4. 我在创建视图时踩过的坑排查实录4.1 “创建视图权限不足”的完整处理过程热搜词里赫然有一条“创建视图权限不足”这是日常 DBA 和开发协作时最常遇到的权限错误。SQL Server 报错通常长这样消息 262级别 14状态 1第 XX 行 在数据库 Test 中拒绝了 CREATE VIEW 权限。数据库级别权限不足。原因很简单当前登录用户在目标数据库里没有创建对象的权限。解决办法是在该库上授予CREATE VIEW权限同时还要有引用表的SELECT权限。以数据库管理员身份执行USE Test; GO GRANT CREATE VIEW TO [你的用户名]; GRANT SELECT ON OBJECT::dbo.employee TO [你的用户名]; GRANT SELECT ON OBJECT::dbo.department TO [你的用户名]; GRANT SELECT ON OBJECT::dbo.sales_order TO [你的用户名];如果还是不行检查用户是否属于数据库角色。开发账号最好只加入db_datareader再单独授予CREATE VIEW不要直接塞进db_owner。这样既能支持开发又不会把整个库的写权限都放开。有人会问为什么我明明能查询基础表却创建不了视图因为“查询数据”和“创建对象”是两种不同权限。你能够查表只说明你有SELECT权限创建视图却还需要对当前 schema 的CREATE权限。理解这一点就不会被这个报错吓住了。4.2 视图查询很慢从“慢SQL优化”角度去查视图慢是另一个高发问题。很多人觉得用了视图查询就会被“预先优化”其实普通视图每次执行都会实时查表优化器对它的处理跟你直接执行那段 SELECT 没有什么本质区别。所以视图查询慢第一件事就是打开执行计划看内部语句。我常用的排查路径是先看“实际执行计划”中耗时最高的操作确认是不是缺索引。比如v_sales_order_detail里按sales_order.emp_no关联employee.emp_no如果两个表数据量大、关联字段没有索引就会出现嵌套循环配大表扫描几百毫秒甚至几秒。这时候不是去给视图加什么选项而是去基础表上补索引CREATE INDEX IX_sales_order_emp_no ON dbo.sales_order(emp_no); CREATE INDEX IX_employee_dept_id ON dbo.employee(dept_id);第二个常见原因是视图套视图。有人为了提高复用度建了v1然后用v1建了v2再用v2建了v3最后查v3时嵌套层次很深执行计划膨胀优化器也不一定能把中间层合并掉。遇到这种慢 SQL把视图展开原样改成基础表 JOIN往往立竿见影。再说一遍视图的命名是“封装复杂逻辑”不是“让查询一定变快”。如果非要用视图提升性能请考虑索引视图见第 5 章。4.3 SQL Server 连接时出现 SSL 相关的连接错误SSMS 实操过程中很多新手不是被 SQL 语法难倒而是连连接都没建起来。热搜词里那条“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接”就非常典型。这类报错常见于 SQL Server 开启“强制加密”后客户端 SSMS 却无法验证服务器证书或者客户端信任级别设置不一致。解决办法有几个方向在连接对话框点击“选项” - “加密”尝试勾选“信任服务器证书”但前提是测试环境或者可控内网环境。检查 SQL Server 的证书配置确认服务器安装了有效证书。如果只是本地开发可以暂时关闭服务器的强制加密但我更建议保留加密并补齐证书信任链。需要注意我不建议为了消除报错就在公网环境下关闭加密或随意跳过证书验证。安全底线不能妥协。连接问题通常是环境问题不是视图语法问题所以别再纠结 SQL 写没写对了。4.4 修改视图时“DROP后CREATE”带来的权限丢失我见过很多老开发改视图时特别喜欢写IF OBJECT_ID(dbo.v_demo, V) IS NOT NULL DROP VIEW dbo.v_demo; GO CREATE VIEW dbo.v_demo AS SELECT ...坏处很明显每 DROP 一次视图上原有的GRANT SELECT权限、以及相关依赖关系比如下游存储过程对它的引用元数据全部丢失。如果这是报表系统正在用的视图很可能造成间歇性访问失败。更稳的做法是直接ALTER VIEW。它会保留对象本身只替换内部查询逻辑ALTER VIEW dbo.v_demo AS SELECT ...同时ALTER VIEW也保留了视图上的权限设置。这一点在正式环境里非常重要。我现在的习惯是除非视图结构变化太大必须重建否则一律用ALTER VIEW。4.5 给视图起名时的小雷区给视图命名也有讲究。不要用sp_开头SQL Server 会优先把它当成系统存储过程来处理每次调用都可能先查master数据库性能受影响。不要用系统保留字和空格。建议统一前缀比如v_或view_一看就知道是视图。还要注意SQL Server 有个坑视图名和基础表名在同一个 schema 不能重复。想绕开的话可以让视图建在独立 schema 下比如report.v_sales_order_detail。这样报表 schema 和业务表 schema 分离权限隔离也更干净。5. 视图创建后的维护经验与安全建议5.1 当视图越来越多怎么避免“套娃式垃圾视图”我见过最夸张的情况一个小项目里塞了 80 多个视图很多视图只被用了一两次还有 A 视图引用 B 视图、B 视图又引用 A 视图的循环依赖。创建视图一定要有节制。我的经验是每个视图都必须能说清楚“服务哪个业务场景”并且定期清理没人用的视图。你可以用下面这个查询结合sys.sql_expression_dependencies找出视图之间相互引用关系定位没用到的视图SELECT referencing.referencing_schema_name, referencing.referencing_entity_name, referenced.referenced_schema_name, referenced.referenced_entity_name FROM sys.sql_expression_dependencies AS deps JOIN sys.objects AS referencing ON deps.referencing_id referencing.object_id JOIN sys.objects AS referenced ON deps.referenced_id referenced.object_id WHERE referencing.type V AND referenced.type V;不要怕删视图。删除一个没人用的视图比留着一个每天都在产生疑惑的对象要好得多。视图本质上是代码代码需要有维护者没人维护的代码早晚是负担。5.2 用索引视图把“虚拟表”变成“可加速实体”普通视图性能可能不理想但 SQL Server 支持“索引视图”相当于把视图计算结果实体化存储并且自动维护更新。效果类似其他数据库里的物化视图。创建索引视图有比较严格的前提视图必须使用WITH SCHEMABINDING基础表必须存在唯一聚集索引视图里的连接必须明确、不能使用子查询某些条件等等。比如给上面的销售明细视图创建索引流程大致是-- 先改成模式绑定 ALTER VIEW v_sales_order_detail WITH SCHEMABINDING AS SELECT ... GO -- 创建唯一聚集索引 CREATE UNIQUE CLUSTERED INDEX IX_v_sales_order_detail_order_id ON dbo.v_sales_order_detail(order_id);建了聚集索引后还可以在视图上继续建非聚集索引进一步提升聚合查询速度。但请记住索引视图有维护成本。每次基础表INSERT/UPDATE/DELETE索引视图都要同步更新如果你的业务写多读少千万别为了查询快一点而把写入拖慢。我很建议在报表库、数仓层使用索引视图而事务型业务库要谨慎。5.3 用视图做权限隔离时要补的一块短板视图最常见的权限用途是隐藏敏感字段但只有视图是不够的。比如用户有db_datareader角色他可能仍然可以直接SELECT基础表只要基础表权限没封住视图的隔离就是摆设。正确做法分两层底层表只授权给管理账号或服务账号不直接授权给报表用户报表用户只拥有视图的SELECT权限。如果你不希望用户绕过视图直接查基础表甚至可以创建独立 schema比如sec放基础表再创建一个reportschema 放视图权限交界非常清晰。我在项目里做权限模型时最讨厌的就是“表权限和视图权限乱成一锅粥”的情况权限设计越简单后面审计越轻松。5.4 视图不是防 SQL 注入的盾牌创建视图能隐藏字段但它不能防 SQL 注入。如果你把用户输入的参数直接拼进 SQL 字符串然后去查询那个视图注入风险依旧存在。比如很多人喜欢写-- 错误示范拼接 SQL DECLARE sql NVARCHAR(MAX) SELECT * FROM v_sales_order_detail WHERE customer_name input ; EXEC(sql);如果input被传入客户A OR 11--过滤条件就形同虚设。正确做法是参数化查询在数据库里可以用sp_executesqlDECLARE sql NVARCHAR(MAX) NSELECT * FROM dbo.v_sales_order_detail WHERE customer_name cust; EXEC sp_executesql sql, Ncust NVARCHAR(50), cust input;在应用层用 ADO.NET、JDBC 等框架的SqlParameter/PreparedStatement传参数也是同样的道理。视图能帮你统一口径、控制权限但注入防护还是要靠编码习惯。回到创建视图这件事本身。很多人学 SQL 学到视图会把它当成一个特别高级的功能其实它只是把一条 SELECT 语句封装成了可复用的数据库对象。在这个基础上真正让你水平拉开差距的是对权限、性能、维护边界的理解。我自己喜欢的做法是先写一条清晰的 SELECT确认数据没问题再套一层 CREATE VIEW最后做权限和索引设计。整个过程听起来简单但每步都做扎实比背一百个语法规则都管用。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。