SQLite 视图创建

SQLiteBeginner
立即练习

介绍

在这个实验(Lab)中,我们将探索 SQLite 视图的创建,重点是构建复杂的视图、通过它们进行查询、通过可更新视图进行更新,以及移除过时的视图。

我们将首先了解视图,将其视为基于 SQL 语句结果集的虚拟表,这对于简化查询和控制数据访问非常有用。本实验(Lab)将指导你从单个表(例如 employees 表)创建简单的视图,然后逐步创建涉及表之间连接的更复杂的视图,例如连接 employeesdepartments 表。你将学习如何像查询常规表一样查询这些视图,并探索通过可更新视图更新数据的可能性,以及如何在不再需要视图时正确地移除它们。

创建表:employees(员工)和 departments(部门)

在此步骤中,你将创建两个表,employeesdepartments,并插入一些示例数据。这些表将用于在后续步骤中创建和查询视图。

首先,通过在终端中运行以下命令来打开 SQLite shell:

sqlite3 /home/labex/project/employees.db

此命令打开 SQLite shell 并连接到 employees.db 数据库。如果数据库文件不存在,SQLite 将创建它。

现在,使用以下 SQL 语句创建 employees 表:

CREATE TABLE employees (
    id INTEGER PRIMARY KEY,
    first_name TEXT,
    last_name TEXT,
    department TEXT,
    salary REAL
);

此 SQL 语句创建一个名为 employees 的表,其中包含五列:idfirst_namelast_namedepartmentsalaryid 列是表的主键(primary key)。

接下来,将一些示例数据插入到 employees 表中:

INSERT INTO employees (first_name, last_name, department, salary) VALUES
('John', 'Doe', 'Sales', 50000.00),
('Jane', 'Smith', 'Marketing', 60000.00),
('Peter', 'Jones', 'Sales', 55000.00),
('Mary', 'Brown', 'IT', 70000.00);

此 SQL 语句将四行数据插入到 employees 表中。

现在,使用以下 SQL 语句创建 departments 表:

CREATE TABLE departments (
    id INTEGER PRIMARY KEY,
    name TEXT,
    location TEXT
);

此 SQL 语句创建一个名为 departments 的表,其中包含三列:idnamelocationid 列是表的主键(primary key)。

接下来,将一些示例数据插入到 departments 表中:

INSERT INTO departments (name, location) VALUES
('Sales', 'New York'),
('Marketing', 'London'),
('IT', 'San Francisco');

此 SQL 语句将三行数据插入到 departments 表中。

你可以通过查询表来验证表的创建和数据插入:

SELECT * FROM employees;
SELECT * FROM departments;

这些命令将分别显示 employeesdepartments 表的内容。

创建一个简单视图

在此步骤中,你将创建一个名为 employee_info 的简单视图,该视图从 employees 表中选择特定的列。

视图是基于 SQL 语句的结果集(result-set)的虚拟表。它简化了复杂的查询,并提供了一定程度的抽象(abstraction)。

要创建 employee_info 视图,请在 SQLite shell 中运行以下 SQL 语句:

CREATE VIEW employee_info AS
SELECT id, first_name, last_name, department
FROM employees;

此 SQL 语句创建一个名为 employee_info 的视图,该视图从 employees 表中选择 idfirst_namelast_namedepartment 列。

现在,你可以像查询表一样查询该视图:

SELECT * FROM employee_info;

此命令将显示 employee_info 视图的内容,该视图是 employees 表中列的子集。

创建一个包含连接的复杂视图

在此步骤中,你将创建一个更复杂的视图,名为 employee_department_info,它连接(join)了 employeesdepartments 表。

连接表允许你基于相关的列,将来自多个表的数据组合在一起。

要创建 employee_department_info 视图,请在 SQLite shell 中运行以下 SQL 语句:

CREATE VIEW employee_department_info AS
SELECT
    e.first_name,
    e.last_name,
    e.department,
    d.location
FROM
    employees e
JOIN
    departments d ON e.department = d.name;

此 SQL 语句创建一个名为 employee_department_info 的视图,该视图通过 department 列连接 employeesdepartments 表。它选择员工的名字(first name)、姓氏(last name)、部门(department)以及部门的所在地(location)。

现在,你可以查询该视图以查看组合后的数据:

SELECT * FROM employee_department_info;

此命令将显示 employee_department_info 视图的内容,显示员工信息以及他们所在部门的所在地。

创建一个包含聚合函数的视图

在此步骤中,你将创建一个名为 department_salary_stats 的视图,该视图使用聚合函数来计算每个部门的平均工资(average salary)。

聚合函数对一组值执行计算并返回单个结果。

要创建 department_salary_stats 视图,请在 SQLite shell 中运行以下 SQL 语句:

CREATE VIEW department_salary_stats AS
SELECT
    department,
    AVG(salary) AS average_salary
FROM
    employees
GROUP BY
    department;

此 SQL 语句创建一个名为 department_salary_stats 的视图,该视图使用 AVG 函数计算每个部门的平均工资,并使用 GROUP BY 子句按部门对结果进行分组。

现在,你可以查询该视图以查看每个部门的平均工资:

SELECT * FROM department_salary_stats;

此命令将显示 department_salary_stats 视图的内容,显示每个部门的平均工资。

通过可更新视图更新数据

在这一步中,你将了解 SQLite 视图的局限性,以及如何使用 INSTEAD OF 触发器创建真正可更新的视图。

重要提示: 默认情况下,SQLite 视图是只读的。你不能直接通过视图 UPDATE、INSERT 或 DELETE 数据。但是,你可以使用 INSTEAD OF 触发器创建可更新的视图。

首先,让我们通过尝试直接更新现有的视图来了解其局限性:

UPDATE employee_info
SET department = 'HR'
WHERE id = 1;

这将失败并报错,因为默认情况下 SQLite 视图是只读的。

要创建真正可更新的视图,我们需要使用 INSTEAD OF 触发器。让我们重新创建 employee_info 视图,并为更新添加一个 INSTEAD OF 触发器:

DROP VIEW IF EXISTS employee_info;

CREATE VIEW employee_info AS
SELECT id, first_name, last_name, department
FROM employees;

现在,创建一个 INSTEAD OF 触发器来处理 UPDATE 操作:

CREATE TRIGGER update_employee_info
INSTEAD OF UPDATE ON employee_info
BEGIN
    UPDATE employees
    SET first_name = NEW.first_name,
        last_name = NEW.last_name,
        department = NEW.department
    WHERE id = OLD.id;
END;

现在,你可以通过视图更新数据:

UPDATE employee_info
SET department = 'HR'
WHERE id = 1;

这个 UPDATE 语句现在将起作用,因为 INSTEAD OF 触发器将更新重定向到底层的 employees 表。

你可以通过直接查询 employees 表来验证更新:

SELECT * FROM employees WHERE id = 1;

此命令将显示 employees 表中 id = 1 的行,你应该看到 department 列已更新为 'HR'。

移除过时的视图和触发器

在这一步,你将移除在之前的步骤中创建的视图和触发器。

随着你的数据库不断发展,一些视图和触发器可能会变得过时或不必要。移除这些对象对于维护一个干净且高效的数据库模式至关重要。

首先,移除 INSTEAD OF 触发器:

DROP TRIGGER IF EXISTS update_employee_info;

然后移除视图。要移除一个视图,使用 DROP VIEW 语句。例如,要移除 employee_info 视图,运行以下命令:

DROP VIEW IF EXISTS employee_info;

IF EXISTS 子句可以防止在视图不存在时发生错误。

同时移除其他视图:

DROP VIEW IF EXISTS employee_department_info;
DROP VIEW IF EXISTS department_salary_stats;

你可以通过查询 sqlite_master 表来验证视图是否已被移除:

SELECT name FROM sqlite_master WHERE type='view';

这个命令应该返回一个空的结果,表明数据库中没有视图。

最后,退出 SQLite shell:

.exit

这个命令会关闭与 employees.db 数据库的连接,并将你返回到 Linux 终端。

总结

在这个实验(Lab)中,你学习了如何在 SQLite 中创建、查询、更新和删除视图(view)。你首先创建了基于单个表的简单视图,然后逐步过渡到涉及连接(join)和聚合函数(aggregate function)的更复杂的视图。你发现 SQLite 视图默认是只读的,但学习了如何使用 INSTEAD OF 触发器(trigger)创建真正可更新的视图。你还学习了如何正确地删除过时的视图和触发器,以维护一个干净的数据库模式(schema)。这些技能对于简化复杂查询、控制数据访问以及有效地管理你的 SQLite 数据库至关重要。