SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019 视图操作 — 语法知识点及使用方法详解(16)

SQL Server 2019 视图操作 --- 语法知识点及使用方法详解


一、视图概述

1.1 视图的概念

视图(View) 是一个虚拟表,其内容由定义它的查询语句动态生成。视图不存储实际数据(除非是索引视图),而是保存 SELECT 语句的定义。每次查询视图时,SQL Server 都会执行该 SELECT 语句并返回结果。

📌 核心特点

  • 虚拟表,无物理存储(索引视图除外)
  • 基于一个或多个基表(或其它视图)
  • 可以像表一样被查询(SELECT)
  • 在特定条件下可更新(INSERT/UPDATE/DELETE)

1.2 视图的分类

类型 说明 特点
标准视图 最常见类型,由 SELECT 语句定义 无物理数据,每次查询执行底层语句
索引视图(物化视图) 创建聚集索引后物理存储数据 提升复杂查询性能,占用存储空间,维护成本高
分区视图 跨多个服务器或表的 UNION ALL 视图 用于分布式数据库或水平分表场景
系统视图 SQL Server 内置,如 sys.tables, sys.columns 用于查询元数据

⚠️ 本章主要讲解标准视图,索引视图将在性能优化章节详述。


1.3 视图的优点和作用

优点与作用

  1. 简化复杂查询:封装多表 JOIN、聚合、计算列等复杂逻辑。
  2. 安全性控制:限制用户访问特定列或行(如屏蔽敏感字段)。
  3. 逻辑独立性:表结构变更时,可通过修改视图保持应用程序接口稳定。
  4. 数据抽象:向用户提供定制化数据视图,隐藏底层表结构。
  5. 重用性:一次定义,多次使用,减少重复代码。
  6. 兼容性:为旧程序提供兼容接口,即使底层表结构已变更。

二、创建视图

2.1 使用视图设计器创建视图(SSMS GUI)

步骤简述(因无法展示图形界面,仅文字说明):

  1. 在 SSMS 中展开数据库 → "视图" 节点。
  2. 右键 → "新建视图"。
  3. 在"添加表"对话框中选择基表。
  4. 在网格中选择列,设置筛选条件、排序等。
  5. 保存并命名视图(如 vw_EmployeeInfo)。
    ⚠️ 生产环境建议:优先使用 T-SQL 脚本,便于版本控制和自动化部署。

2.2 使用 Transact-SQL 命令创建视图

基本语法:
sql 复制代码
CREATE [OR ALTER] VIEW [schema_name.]view_name [ (column_name [ ,...n ] ) ]
[ WITH 
    { ENCRYPTION | SCHEMABINDING | VIEW_METADATA } 
]
AS
    select_statement
[ WITH CHECK OPTION ]
关键选项说明:
  • CREATE OR ALTER:SQL Server 2016 SP1+,若不存在则创建,存在则修改。
  • (column_name [,...n]):显式指定视图列名(当 SELECT 包含表达式或函数时必需)。
  • WITH ENCRYPTION:加密视图定义文本(防止被 sp_helptext 查看)。
  • WITH SCHEMABINDING:绑定视图到基表架构,防止基表被修改或删除(需使用 schema.object 格式引用对象)。
  • WITH CHECK OPTION:强制所有通过视图的修改操作必须满足视图的 WHERE 条件。
  • WITH VIEW_METADATA:使视图在元数据中表现为基表(用于某些 ORM 工具)。

案例1:创建基础员工信息视图
sql 复制代码
-- 创建视图:显示员工基本信息(隐藏敏感字段如Salary)
CREATE VIEW dbo.vw_EmployeeBasicInfo
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    FirstName + ' ' + LastName AS FullName, -- 计算列
    DeptID
FROM dbo.Employees;
GO

-- 查询视图
SELECT * FROM dbo.vw_EmployeeBasicInfo;
GO

注释

  • 视图隐藏了 Salary 字段,增强安全性。
  • FullName 是计算列,在查询时动态生成。

案例2:创建带条件筛选的视图(高薪员工)
sql 复制代码
-- 创建视图:显示薪资高于8000的员工
CREATE VIEW dbo.vw_HighSalaryEmployees
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    Salary,
    DeptID
FROM dbo.Employees
WHERE Salary > 8000; -- 筛选条件
GO

-- 查询视图
SELECT * FROM dbo.vw_HighSalaryEmployees;
GO

注释

  • 视图仅包含满足 Salary > 8000 的行。
  • 用户无需知道筛选条件,直接查询视图即可。

案例3:创建多表连接视图(员工+部门)
sql 复制代码
-- 创建视图:员工及其部门信息
CREATE VIEW dbo.vw_EmployeeDepartment
AS
SELECT 
    e.EmployeeID,
    e.FirstName,
    e.LastName,
    e.Salary,
    d.DeptName,
    d.DeptID
FROM dbo.Employees e
INNER JOIN dbo.Departments d ON e.DeptID = d.DeptID;
GO

-- 查询视图
SELECT * FROM dbo.vw_EmployeeDepartment;
GO

注释

  • 封装了 JOIN 逻辑,用户无需关心表关联。
  • 简化了复杂查询,提高开发效率。

案例4:创建带架构绑定和检查选项的视图
sql 复制代码
-- 创建架构绑定视图:确保基表结构不被修改
CREATE VIEW dbo.vw_ITDepartmentEmployees
WITH SCHEMABINDING -- 绑定架构
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    Salary
FROM dbo.Employees
WHERE DeptID = 1; -- 假设1是IT部门
GO

-- 尝试修改基表(会失败,因为视图绑定了架构)
-- ALTER TABLE dbo.Employees DROP COLUMN FirstName; 
-- 错误:不能 ALTER TABLE 'Employees',因为它正被视图 'vw_ITDepartmentEmployees' 使用。

-- 创建带CHECK OPTION的视图:确保插入/更新的数据满足条件
CREATE VIEW dbo.vw_SalaryAbove5000
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    Salary
FROM dbo.Employees
WHERE Salary > 5000
WITH CHECK OPTION; -- 强制检查
GO

-- 测试CHECK OPTION
-- 以下插入会失败,因为Salary=4000不满足视图条件
-- INSERT INTO dbo.vw_SalaryAbove5000 (FirstName, LastName, Salary) 
-- VALUES ('Test', 'User', 4000);
-- 错误:试图通过视图执行的 INSERT 或 UPDATE 语句已违反 WITH CHECK OPTION 约束。
GO

注释

  • SCHEMABINDING 保护基表结构,但限制了灵活性。
  • WITH CHECK OPTION 确保数据一致性,防止通过视图插入"不可见"数据。

三、修改视图

语法:

sql 复制代码
ALTER VIEW [schema_name.]view_name [ (column_name [ ,...n ] ) ]
[ WITH 
    { ENCRYPTION | SCHEMABINDING | VIEW_METADATA } 
]
AS
    select_statement
[ WITH CHECK OPTION ]

或使用 CREATE OR ALTER VIEW(推荐)。


案例5:修改视图 --- 增加新列
sql 复制代码
-- 修改视图:在vw_EmployeeBasicInfo中增加入职日期(假设Employees表有HireDate字段)
IF COL_LENGTH('dbo.Employees', 'HireDate') IS NULL
BEGIN
    ALTER TABLE dbo.Employees ADD HireDate DATE DEFAULT GETDATE();
END
GO

-- 使用ALTER VIEW修改
ALTER VIEW dbo.vw_EmployeeBasicInfo
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    FirstName + ' ' + LastName AS FullName,
    DeptID,
    HireDate -- 新增列
FROM dbo.Employees;
GO

-- 或使用CREATE OR ALTER(推荐)
CREATE OR ALTER VIEW dbo.vw_EmployeeBasicInfo
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    FirstName + ' ' + LastName AS FullName,
    DeptID,
    HireDate
FROM dbo.Employees;
GO

-- 验证修改
SELECT * FROM dbo.vw_EmployeeBasicInfo;
GO

注释

  • ALTER VIEW 要求视图必须存在。
  • CREATE OR ALTER 更灵活,适用于部署脚本。

四、查看视图信息

方法1:使用系统存储过程 sp_help

sql 复制代码
-- 查看视图基本信息
EXEC sp_help 'dbo.vw_EmployeeBasicInfo';
GO

方法2:使用 sp_helptext 查看定义

sql 复制代码
-- 查看视图的T-SQL定义
EXEC sp_helptext 'dbo.vw_EmployeeBasicInfo';
GO

方法3:查询系统视图 sys.viewssys.sql_modules

sql 复制代码
-- 查询所有用户定义视图
SELECT 
    name AS ViewName,
    create_date,
    modify_date
FROM sys.views
WHERE is_ms_shipped = 0; -- 排除系统视图
GO

-- 查询特定视图的定义
SELECT 
    definition
FROM sys.sql_modules
WHERE object_id = OBJECT_ID('dbo.vw_EmployeeBasicInfo');
GO

方法4:查看视图依赖关系

sql 复制代码
-- 查看视图依赖的基表(SQL Server 2008+)
SELECT 
    referencing_entity_name = OBJECT_NAME(referencing_id),
    referenced_entity_name = OBJECT_NAME(referenced_id),
    referenced_class_desc
FROM sys.sql_expression_dependencies
WHERE referencing_id = OBJECT_ID('dbo.vw_EmployeeDepartment');
GO

注释

  • sp_helptext 是最常用方法。
  • 系统视图提供更多元数据信息,适合程序化查询。

五、使用视图修改数据

⚠️ 重要前提:并非所有视图都可更新!可更新视图需满足:

  • SELECT 列表中不能包含聚合函数、DISTINCT、GROUP BY、UNION 等。
  • 不能包含计算列(除非是 INSTEAD OF 触发器)。
  • FROM 子句必须引用基表(不能是子查询或连接多个表,除非有 INSTEAD OF 触发器)。
  • 不能包含 TOP、OFFSET FETCH 等。

5.1 通过视图向基本表中插入数据

案例6:通过简单视图插入数据
sql 复制代码
-- 创建可插入视图(仅包含基表所有非空列)
CREATE OR ALTER VIEW dbo.vw_EmployeeInsert
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    Salary,
    DeptID
FROM dbo.Employees;
GO

-- 插入数据(EmployeeID是IDENTITY,可省略)
INSERT INTO dbo.vw_EmployeeInsert (FirstName, LastName, Salary, DeptID)
VALUES ('张', '三', 9000, 2);

-- 验证插入
SELECT * FROM dbo.Employees WHERE FirstName = '张' AND LastName = '三';
GO

注释

  • 视图包含基表所有非空列(除IDENTITY列外),可直接插入。
  • 若视图缺少非空列,插入会失败。

5.2 通过视图更新基本表中的数据

案例7:通过视图更新薪资
sql 复制代码
-- 使用之前创建的vw_HighSalaryEmployees视图更新数据
UPDATE dbo.vw_HighSalaryEmployees
SET Salary = Salary + 1000 -- 给高薪员工加薪1000
WHERE EmployeeID = 1; -- 假设员工1薪资>8000

-- 验证更新
SELECT Salary FROM dbo.Employees WHERE EmployeeID = 1;
GO

注释

  • 更新操作直接作用于基表。
  • 若视图包含 WHERE 条件,更新后数据可能"消失"(不再满足条件)。

5.3 通过视图删除基本表中的数据

案例8:通过视图删除数据
sql 复制代码
-- 删除通过视图可见的员工
DELETE FROM dbo.vw_HighSalaryEmployees
WHERE EmployeeID = 2; -- 假设员工2薪资>8000

-- 验证删除
SELECT * FROM dbo.Employees WHERE EmployeeID = 2;
GO

注释

  • 删除操作作用于基表。
  • 删除后数据从视图和基表中同时消失。

5.4 使用 INSTEAD OF 触发器实现复杂视图更新

当视图包含多表连接、计算列等不可直接更新的情况时,可使用 INSTEAD OF 触发器。

案例9:为多表视图创建 INSTEAD OF INSERT 触发器
sql 复制代码
-- 创建视图:员工+部门(不可直接插入)
CREATE OR ALTER VIEW dbo.vw_EmployeeWithDept
AS
SELECT 
    e.EmployeeID,
    e.FirstName,
    e.LastName,
    e.Salary,
    d.DeptName -- 来自另一个表
FROM dbo.Employees e
INNER JOIN dbo.Departments d ON e.DeptID = d.DeptID;
GO

-- 创建INSTEAD OF INSERT触发器
CREATE TRIGGER trg_InsteadOfInsert_vw_EmployeeWithDept
ON dbo.vw_EmployeeWithDept
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;

    -- 声明变量
    DECLARE @DeptID INT;

    -- 获取部门ID(根据DeptName查找)
    SELECT @DeptID = d.DeptID
    FROM inserted i
    INNER JOIN dbo.Departments d ON i.DeptName = d.DeptName;

    -- 检查部门是否存在
    IF @DeptID IS NULL
    BEGIN
        RAISERROR('部门名称不存在!', 16, 1);
        RETURN;
    END

    -- 插入到Employees表
    INSERT INTO dbo.Employees (FirstName, LastName, Salary, DeptID)
    SELECT FirstName, LastName, Salary, @DeptID
    FROM inserted;
END
GO

-- 通过视图插入数据(触发器会处理)
INSERT INTO dbo.vw_EmployeeWithDept (FirstName, LastName, Salary, DeptName)
VALUES ('李', '四', 8500, '人事部'); -- 假设"人事部"存在

-- 验证插入
SELECT * FROM dbo.Employees WHERE FirstName = '李' AND LastName = '四';
GO

注释

  • INSTEAD OF 触发器替代默认的插入操作。
  • 在触发器中处理多表逻辑(根据部门名查找ID)。
  • 同样可创建 INSTEAD OF UPDATEINSTEAD OF DELETE 触发器。

六、删除视图

语法:

sql 复制代码
DROP VIEW [IF EXISTS] [schema_name.]view_name [ ,...n ]

案例10:删除视图
sql 复制代码
-- 删除单个视图
DROP VIEW IF EXISTS dbo.vw_EmployeeInsert;

-- 删除多个视图
DROP VIEW IF EXISTS 
    dbo.vw_HighSalaryEmployees,
    dbo.vw_SalaryAbove5000;

-- 传统写法(兼容旧版本)
IF OBJECT_ID('dbo.vw_EmployeeBasicInfo', 'V') IS NOT NULL -- 'V' 表示View
    DROP VIEW dbo.vw_EmployeeBasicInfo;
GO

注释

  • DROP VIEW IF EXISTS 是 SQL Server 2016+ 语法,避免"对象不存在"错误。
  • 删除视图不影响基表数据。

七、综合性案例

综合案例1:销售管理系统 --- 多层视图与数据操作

sql 复制代码
-- 场景:构建销售数据视图体系,支持查询、插入、更新

-- 1. 创建产品表
CREATE TABLE dbo.Products (
    ProductID INT IDENTITY(1,1) PRIMARY KEY,
    ProductName NVARCHAR(100) NOT NULL,
    Category NVARCHAR(50),
    UnitPrice DECIMAL(10,2) NOT NULL,
    Stock INT NOT NULL DEFAULT 0
);
GO

-- 2. 创建订单表
CREATE TABLE dbo.Orders (
    OrderID INT IDENTITY(1,1) PRIMARY KEY,
    OrderDate DATE DEFAULT GETDATE(),
    CustomerName NVARCHAR(100) NOT NULL
);
GO

-- 3. 创建订单明细表
CREATE TABLE dbo.OrderDetails (
    DetailID INT IDENTITY(1,1) PRIMARY KEY,
    OrderID INT NOT NULL,
    ProductID INT NOT NULL,
    Quantity INT NOT NULL,
    UnitPrice DECIMAL(10,2) NOT NULL, -- 冗余存储,便于历史记录
    FOREIGN KEY (OrderID) REFERENCES dbo.Orders(OrderID),
    FOREIGN KEY (ProductID) REFERENCES dbo.Products(ProductID)
);
GO

-- 插入测试数据
INSERT INTO dbo.Products (ProductName, Category, UnitPrice, Stock) VALUES
('笔记本电脑', '电子产品', 5000.00, 50),
('鼠标', '电子产品', 100.00, 200),
('键盘', '电子产品', 200.00, 150);

INSERT INTO dbo.Orders (CustomerName) VALUES ('张三'), ('李四');

INSERT INTO dbo.OrderDetails (OrderID, ProductID, Quantity, UnitPrice) VALUES
(1, 1, 1, 5000.00), -- 张三买1台电脑
(1, 2, 2, 100.00),  -- 张三买2个鼠标
(2, 3, 1, 200.00);  -- 李四买1个键盘
GO

-- 4. 创建基础视图:订单详情(连接三表)
CREATE OR ALTER VIEW dbo.vw_OrderDetailsFull
AS
SELECT 
    od.DetailID,
    o.OrderID,
    o.OrderDate,
    o.CustomerName,
    p.ProductName,
    p.Category,
    od.Quantity,
    od.UnitPrice,
    od.Quantity * od.UnitPrice AS TotalPrice
FROM dbo.OrderDetails od
INNER JOIN dbo.Orders o ON od.OrderID = o.OrderID
INNER JOIN dbo.Products p ON od.ProductID = p.ProductID;
GO

-- 5. 创建聚合视图:客户订单汇总
CREATE OR ALTER VIEW dbo.vw_CustomerOrderSummary
AS
SELECT 
    CustomerName,
    COUNT(DISTINCT OrderID) AS OrderCount,
    SUM(Quantity) AS TotalQuantity,
    SUM(TotalPrice) AS TotalAmount
FROM dbo.vw_OrderDetailsFull
GROUP BY CustomerName;
GO

-- 6. 创建可更新视图:产品库存视图(用于库存管理)
CREATE OR ALTER VIEW dbo.vw_ProductStock
WITH SCHEMABINDING
AS
SELECT 
    ProductID,
    ProductName,
    Category,
    UnitPrice,
    Stock
FROM dbo.Products;
GO

-- 7. 创建INSTEAD OF触发器:支持通过vw_OrderDetailsFull插入订单
CREATE OR ALTER TRIGGER trg_InsteadOfInsert_vw_OrderDetailsFull
ON dbo.vw_OrderDetailsFull
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @OrderID INT, @ProductID INT;

    BEGIN TRY
        BEGIN TRANSACTION;

        -- 检查客户是否存在订单,不存在则创建新订单
        SELECT @OrderID = OrderID 
        FROM dbo.Orders 
        WHERE CustomerName = (SELECT CustomerName FROM inserted);

        IF @OrderID IS NULL
        BEGIN
            INSERT INTO dbo.Orders (CustomerName) 
            SELECT CustomerName FROM inserted;
            SET @OrderID = SCOPE_IDENTITY();
        END

        -- 获取产品ID
        SELECT @ProductID = ProductID 
        FROM dbo.Products 
        WHERE ProductName = (SELECT ProductName FROM inserted);

        IF @ProductID IS NULL
        BEGIN
            RAISERROR('产品名称不存在!', 16, 1);
            RETURN;
        END

        -- 插入订单明细
        INSERT INTO dbo.OrderDetails (OrderID, ProductID, Quantity, UnitPrice)
        SELECT 
            @OrderID,
            @ProductID,
            Quantity,
            UnitPrice
        FROM inserted;

        -- 更新产品库存(减少)
        UPDATE dbo.Products 
        SET Stock = Stock - (SELECT Quantity FROM inserted)
        WHERE ProductID = @ProductID;

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
        THROW;
    END CATCH
END
GO

-- 8. 测试综合功能

-- (1) 查询订单详情视图
PRINT '=== 订单详情 ===';
SELECT * FROM dbo.vw_OrderDetailsFull;

-- (2) 查询客户汇总视图
PRINT '=== 客户订单汇总 ===';
SELECT * FROM dbo.vw_CustomerOrderSummary;

-- (3) 通过视图更新产品库存
PRINT '=== 更新库存 ===';
UPDATE dbo.vw_ProductStock 
SET Stock = Stock + 100 -- 补货100个鼠标
WHERE ProductName = '鼠标';

SELECT ProductName, Stock FROM dbo.vw_ProductStock WHERE ProductName = '鼠标';

-- (4) 通过视图插入新订单(触发器处理)
PRINT '=== 插入新订单 ===';
INSERT INTO dbo.vw_OrderDetailsFull (CustomerName, ProductName, Quantity, UnitPrice)
VALUES ('王五', '键盘', 2, 200.00); -- 王五买2个键盘

-- 验证插入
SELECT * FROM dbo.vw_OrderDetailsFull WHERE CustomerName = '王五';
SELECT Stock FROM dbo.Products WHERE ProductName = '键盘'; -- 库存应减少2

-- (5) 删除订单(通过视图)
PRINT '=== 删除订单 ===';
DELETE FROM dbo.vw_OrderDetailsFull 
WHERE CustomerName = '王五' AND ProductName = '键盘';

-- 注意:此删除操作会失败,因为视图涉及多表!
-- 需要创建INSTEAD OF DELETE触发器(留作练习)
GO

注释

  • 展示多层视图设计:基础视图 → 聚合视图。
  • 使用 INSTEAD OF INSERT 触发器处理复杂插入逻辑(自动创建订单、更新库存)。
  • 可更新视图 vw_ProductStock 用于直接管理库存。
  • 删除操作需额外触发器支持(未实现,可作为扩展练习)。

综合案例2:员工绩效管理系统 --- 安全视图与数据过滤

sql 复制代码
-- 场景:不同角色用户只能访问特定数据

-- 1. 假设Employees表有Performance字段(绩效评分)
IF COL_LENGTH('dbo.Employees', 'Performance') IS NULL
BEGIN
    ALTER TABLE dbo.Employees ADD Performance DECIMAL(3,2);
    UPDATE dbo.Employees SET Performance = 4.5 WHERE EmployeeID = 1;
    UPDATE dbo.Employees SET Performance = 3.8 WHERE EmployeeID = 2;
    UPDATE dbo.Employees SET Performance = 4.2 WHERE EmployeeID = 3;
END
GO

-- 2. 创建经理视图:可查看所有员工薪资和绩效
CREATE OR ALTER VIEW dbo.vw_ManagerEmployeeView
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    Salary,
    Performance,
    DeptID
FROM dbo.Employees;
GO

-- 3. 创建员工视图:只能查看自己和同部门同事(隐藏薪资和绩效)
CREATE OR ALTER VIEW dbo.vw_EmployeeSelfView
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    DeptID,
    '***' AS Salary, -- 隐藏薪资
    '***' AS Performance -- 隐藏绩效
FROM dbo.Employees;
GO

-- 4. 创建HR视图:可查看薪资但隐藏绩效
CREATE OR ALTER VIEW dbo.vw_HREmployeeView
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    Salary,
    '***' AS Performance, -- 隐藏绩效
    DeptID
FROM dbo.Employees;
GO

-- 5. 创建带行级安全的视图(模拟:员工只能看自己)
-- 假设有当前用户ID(实际应用中可能从登录名映射)
CREATE OR ALTER VIEW dbo.vw_CurrentUserEmployee
AS
SELECT 
    EmployeeID,
    FirstName,
    LastName,
    '***' AS Salary,
    Performance,
    DeptID
FROM dbo.Employees
WHERE EmployeeID = 1; -- 假设当前用户ID=1(实际应动态获取)
GO

-- 6. 测试不同视图

PRINT '=== 经理视图 ===';
SELECT * FROM dbo.vw_ManagerEmployeeView;

PRINT '=== 员工视图 ===';
SELECT * FROM dbo.vw_EmployeeSelfView;

PRINT '=== HR视图 ===';
SELECT * FROM dbo.vw_HREmployeeView;

PRINT '=== 当前用户视图 ===';
SELECT * FROM dbo.vw_CurrentUserEmployee; -- 只显示EmployeeID=1的记录
GO

-- 7. 创建安全插入视图(带CHECK OPTION)
CREATE OR ALTER VIEW dbo.vw_InsertNewEmployee
AS
SELECT 
    FirstName,
    LastName,
    Salary,
    DeptID
FROM dbo.Employees
WHERE Salary > 0 -- 基本约束
WITH CHECK OPTION;
GO

-- 8. 通过安全视图插入新员工
INSERT INTO dbo.vw_InsertNewEmployee (FirstName, LastName, Salary, DeptID)
VALUES ('赵', '六', 7500, 1); -- 成功

-- 尝试插入无效数据(会失败)
-- INSERT INTO dbo.vw_InsertNewEmployee (FirstName, LastName, Salary, DeptID)
-- VALUES ('钱', '七', -1000, 1); -- 失败:违反CHECK OPTION

SELECT * FROM dbo.Employees WHERE FirstName = '赵' AND LastName = '六';
GO

注释

  • 展示基于角色的数据访问控制(RBAC)。
  • 使用视图隐藏敏感字段(薪资、绩效)。
  • WITH CHECK OPTION 确保插入数据符合业务规则。
  • 行级安全可通过视图 WHERE 条件实现(生产环境建议使用 Row-Level Security 功能)。

八、最佳实践与注意事项

✅ 最佳实践:

  1. 命名规范 :使用 vw_ 前缀(如 vw_EmployeeList)。
  2. **避免 SELECT ***:明确指定列名,防止基表结构变更导致视图失效。
  3. 使用 SCHEMABINDING:当需要确保基表结构稳定时。
  4. 谨慎使用 WITH CHECK OPTION:确保数据一致性,但可能限制灵活性。
  5. 性能考虑:复杂视图可能导致查询性能下降,必要时使用索引视图。
  6. 文档化:在视图定义中添加注释说明用途和逻辑。

⚠️ 注意事项:

  1. 视图不提升性能:标准视图只是保存查询,复杂视图可能更慢。
  2. 更新限制 :多表视图通常不可直接更新,需用 INSTEAD OF 触发器。
  3. 依赖管理:修改基表可能影响视图,需测试。
  4. 权限管理:授予用户视图权限而非基表权限,增强安全性。
  5. 避免嵌套过深:视图嵌套过多(视图查视图)会导致维护困难和性能问题。

✅ 本章全面覆盖 SQL Server 视图的创建、管理、数据操作及实战案例。视图是数据库设计中实现数据抽象、安全控制和逻辑简化的强大工具,合理使用可显著提升系统可维护性和安全性!

相关推荐
郑小憨2 小时前
FlinkSQL窗口函数TUMBLE、SESSION 和 HOP的区别
大数据·数据仓库·sql·flink·database
前路不黑暗@3 小时前
Java项目:Java脚手架项目的 B 端用户服务(十四)
android·java·开发语言·spring boot·笔记·学习·spring cloud
锅包一切3 小时前
PART17 一维动态规划
c++·学习·算法·leetcode·动态规划·力扣·刷题
科技林总3 小时前
【系统分析师】9.3 通信与网络安全技术
学习
SQL必知必会3 小时前
SQL 计算百分位数和中位数
数据库·sql
冰暮流星5 小时前
sql语句之union语句
数据库·sql
CappuccinoRose6 小时前
CSS 语法学习文档(十五)
前端·学习·重构·渲染·浏览器
山岚的运维笔记6 小时前
SQL Server笔记 -- 第63章:事务隔离级别
数据库·笔记·sql·microsoft·oracle·sqlserver