MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

SQLite数据库查询操作深入解析

2024-06-203.3k 阅读

SQLite 数据库基础查询操作

在 SQLite 数据库中,最基本且常用的操作之一就是查询数据。查询操作允许我们从数据库表中检索所需的数据。其核心语句是 SELECT 语句,语法结构通常如下:

SELECT column1, column2 FROM table_name;

其中,SELECT 关键字后面跟着要查询的列名,用逗号分隔。FROM 关键字则指定要从哪个表中进行查询。

例如,假设有一个名为 employees 的表,包含 idnameagesalary 列,我们要查询所有员工的姓名和年龄,可以这样写:

SELECT name, age FROM employees;

如果我们想要查询表中的所有列,可以使用通配符 *

SELECT * FROM employees;

虽然使用 * 很方便,但在实际应用中,特别是在大型表中,明确指定所需列可以提高查询性能,因为数据库不需要返回不必要的数据。

条件查询

在实际场景中,我们往往不会查询表中的所有数据,而是根据某些条件进行筛选。这就需要用到 WHERE 子句。WHERE 子句允许我们指定一个或多个条件,只有满足这些条件的行才会被返回。

WHERE 子句的基本语法如下:

SELECT column1, column2 FROM table_name WHERE condition;

常见的条件运算符包括:

  • 等于 (=):用于判断某个列的值是否等于指定的值。例如,要查询 salary 等于 5000 的员工:
SELECT * FROM employees WHERE salary = 5000;
  • 不等于 (!=<>):查询 salary 不等于 5000 的员工:
SELECT * FROM employees WHERE salary != 5000;
  • 大于 (>)大于等于 (>=)小于 (<)小于等于 (<=):用于数值比较。比如查询 age 大于 30 的员工:
SELECT * FROM employees WHERE age > 30;

还可以使用逻辑运算符将多个条件组合起来:

  • 与 (AND):多个条件同时满足。例如,查询 age 大于 30 且 salary 大于 5000 的员工:
SELECT * FROM employees WHERE age > 30 AND salary > 5000;
  • 或 (OR):只要满足其中一个条件即可。查询 age 小于 25 或者 salary 大于 8000 的员工:
SELECT * FROM employees WHERE age < 25 OR salary > 8000;
  • 非 (NOT):对条件取反。比如查询 age 不小于 30 的员工(即 age 大于等于 30):
SELECT * FROM employees WHERE NOT age < 30;

模糊查询

有时候我们不知道确切的值,只知道部分内容,这就需要模糊查询。在 SQLite 中,使用 LIKE 关键字进行模糊查询。LIKE 通常与通配符一起使用,常用的通配符有:

  • 百分号 (%):代表零个或多个字符。例如,要查询姓名以 “J” 开头的员工:
SELECT * FROM employees WHERE name LIKE 'J%';
  • 下划线 (_):代表单个字符。假设我们要查询姓名为三个字符,且第二个字符为 “o” 的员工:
SELECT * FROM employees WHERE name LIKE '_o_';

排序查询

查询结果的顺序有时很重要,我们可以使用 ORDER BY 子句对查询结果进行排序。ORDER BY 语法如下:

SELECT column1, column2 FROM table_name ORDER BY column_name [ASC|DESC];

其中,ASC 表示升序(默认),DESC 表示降序。例如,要按照 salary 从高到低查询员工:

SELECT * FROM employees ORDER BY salary DESC;

如果要按照多个列排序,可以在 ORDER BY 后面依次列出列名,每个列都可以指定排序方式。例如,先按 age 升序,age 相同的情况下按 salary 降序:

SELECT * FROM employees ORDER BY age ASC, salary DESC;

限制查询结果数量

在某些情况下,我们可能只需要获取查询结果的一部分,比如只查看前几条数据。这时可以使用 LIMIT 子句。LIMIT 子句的语法如下:

SELECT column1, column2 FROM table_name LIMIT number;

其中 number 是要返回的行数。例如,要查询 employees 表中薪资最高的前 5 名员工:

SELECT * FROM employees ORDER BY salary DESC LIMIT 5;

LIMIT 还可以与 OFFSET 一起使用,OFFSET 用于指定从结果集的第几行开始返回。例如,要获取第 6 到第 10 名薪资最高的员工:

SELECT * FROM employees ORDER BY salary DESC LIMIT 5 OFFSET 5;

聚合函数查询

聚合函数用于对一组值进行计算,并返回单个值。常见的聚合函数包括:

  • COUNT:用于计算行数。例如,要统计 employees 表中的员工总数:
SELECT COUNT(*) FROM employees;

如果要统计满足某个条件的行数,比如统计 age 大于 30 的员工数:

SELECT COUNT(*) FROM employees WHERE age > 30;
  • SUM:用于计算数值列的总和。计算所有员工的总薪资:
SELECT SUM(salary) FROM employees;
  • AVG:用于计算数值列的平均值。计算员工的平均薪资:
SELECT AVG(salary) FROM employees;
  • MINMAX:分别用于获取数值列的最小值和最大值。获取员工的最低薪资和最高薪资:
SELECT MIN(salary), MAX(salary) FROM employees;

分组查询

分组查询允许我们根据一个或多个列对数据进行分组,并对每个组应用聚合函数。使用 GROUP BY 子句实现分组查询,语法如下:

SELECT column1, aggregate_function(column2) FROM table_name GROUP BY column1;

例如,假设 employees 表中有一个 department 列,我们要统计每个部门的员工数量:

SELECT department, COUNT(*) FROM employees GROUP BY department;

还可以结合 HAVING 子句对分组后的结果进行筛选。HAVINGWHERE 类似,但 WHERE 用于筛选行,而 HAVING 用于筛选分组。例如,只显示员工数量大于 5 的部门:

SELECT department, COUNT(*) FROM employees GROUP BY department HAVING COUNT(*) > 5;

连接查询

当我们需要从多个表中获取相关数据时,就需要使用连接查询。SQLite 支持多种连接类型,包括内连接(INNER JOIN)、外连接(LEFT JOINRIGHT JOINFULL OUTER JOIN)等。

内连接

内连接是最常见的连接类型,它返回两个表中满足连接条件的所有行。语法如下:

SELECT column1, column2 FROM table1 INNER JOIN table2 ON table1.common_column = table2.common_column;

假设有两个表,employees 表包含员工信息,departments 表包含部门信息,employees 表中有一个 department_id 列与 departments 表中的 id 列相关联。要查询每个员工及其所在部门的名称,可以这样写:

SELECT employees.name, departments.department_name
FROM employees
INNER JOIN departments
ON employees.department_id = departments.id;

左连接

左连接返回左表(LEFT JOIN 关键字左边的表)中的所有行,以及右表中满足连接条件的行。如果右表中没有匹配的行,则返回 NULL 值。语法如下:

SELECT column1, column2 FROM table1 LEFT JOIN table2 ON table1.common_column = table2.common_column;

例如,要查询所有员工及其所在部门的名称,即使某个员工没有分配到部门(即 department_idNULL),也能显示该员工信息:

SELECT employees.name, departments.department_name
FROM employees
LEFT JOIN departments
ON employees.department_id = departments.id;

右连接

右连接与左连接相反,它返回右表中的所有行,以及左表中满足连接条件的行。语法如下:

SELECT column1, column2 FROM table1 RIGHT JOIN table2 ON table1.common_column = table2.common_column;

全外连接

全外连接返回两个表中的所有行。如果某一行在另一个表中没有匹配的行,则对应的列返回 NULL 值。不过,SQLite 本身并不直接支持 FULL OUTER JOIN,但可以通过 UNION 结合 LEFT JOINRIGHT JOIN 来模拟:

SELECT column1, column2 FROM table1 LEFT JOIN table2 ON table1.common_column = table2.common_column
UNION
SELECT column1, column2 FROM table1 RIGHT JOIN table2 ON table1.common_column = table2.common_column;

子查询

子查询是指在一个 SELECT 语句中嵌套另一个 SELECT 语句。子查询可以用于多种场景,例如在 WHERE 子句中作为条件,或者作为一个临时表与其他表进行连接。

例如,要查询薪资高于平均薪资的员工:

SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

这里,内部的子查询 SELECT AVG(salary) FROM employees 先计算出平均薪资,然后外部查询根据这个平均薪资值筛选出薪资高于它的员工。

子查询也可以用于连接操作。假设有一个 orders 表记录订单信息,其中有 customer_id 列关联到 customers 表的 id 列。我们要查询下单金额最高的客户信息,可以这样写:

SELECT * FROM customers
WHERE id = (SELECT customer_id FROM orders ORDER BY amount DESC LIMIT 1);

自连接

自连接是指一个表与自身进行连接。这种情况通常用于处理具有层次结构或递归关系的数据。例如,假设有一个 employees 表,其中有 employee_idmanager_id 列,manager_id 指向该员工的经理的 employee_id。要查询每个员工及其经理的姓名,可以这样实现自连接:

SELECT e.employee_name AS employee, m.employee_name AS manager
FROM employees e
JOIN employees m ON e.manager_id = m.employee_id;

在这个查询中,我们将 employees 表分别命名为 e(代表员工)和 m(代表经理),通过 manager_idemployee_id 进行连接,从而获取员工及其经理的信息。

使用视图进行查询

视图是一个虚拟表,它的结果集来自一个或多个表的查询。视图可以简化复杂的查询,提高数据的安全性和可维护性。创建视图的语法如下:

CREATE VIEW view_name AS
SELECT column1, column2 FROM table1 [JOIN table2 ON table1.common_column = table2.common_column];

例如,我们创建一个视图来显示每个部门的员工数量和平均薪资:

CREATE VIEW department_summary AS
SELECT department, COUNT(*) AS employee_count, AVG(salary) AS average_salary
FROM employees
GROUP BY department;

创建好视图后,就可以像查询普通表一样查询视图:

SELECT * FROM department_summary;

索引与查询优化

索引是一种特殊的数据结构,它可以提高查询性能。在 SQLite 中,创建索引的语法如下:

CREATE INDEX index_name ON table_name (column1, column2);

例如,在 employees 表的 salary 列上创建索引:

CREATE INDEX idx_salary ON employees (salary);

当我们查询 salary 相关的条件时,如 SELECT * FROM employees WHERE salary > 5000;,数据库可以利用这个索引快速定位到满足条件的行,而不需要全表扫描。

不过,索引也不是越多越好,因为创建和维护索引会消耗额外的存储空间和时间。在设计索引时,需要根据实际的查询需求来创建,通常在经常用于 WHERE 子句、JOIN 子句中的列上创建索引。

事务与查询

事务是一组数据库操作,这些操作要么全部成功执行,要么全部不执行。在 SQLite 中,可以使用以下语句来管理事务:

BEGIN; -- 开始一个事务
-- 一系列查询操作
COMMIT; -- 提交事务,使操作永久生效

例如,假设我们要对 employees 表进行两个操作,先更新某个员工的薪资,再插入一条新的员工记录:

BEGIN;
UPDATE employees SET salary = salary * 1.1 WHERE employee_id = 1;
INSERT INTO employees (name, age, salary) VALUES ('New Employee', 25, 4000);
COMMIT;

如果在事务执行过程中出现错误,可以使用 ROLLBACK 语句回滚事务,撤销所有未提交的操作:

BEGIN;
-- 操作语句
ROLLBACK; -- 回滚事务

复杂查询案例分析

假设我们有以下几个表:

  • customers 表:包含客户信息,有 customer_idcustomer_namephone 等列。
  • orders 表:记录订单信息,有 order_idcustomer_idorder_datetotal_amount 等列。
  • order_items 表:记录订单中的商品明细,有 order_item_idorder_idproduct_idquantityprice 等列。
  • products 表:存储商品信息,有 product_idproduct_namecategory 等列。

案例 1:查询每个客户的订单总数和总金额

SELECT c.customer_name, COUNT(o.order_id) AS order_count, SUM(o.total_amount) AS total_amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_name;

在这个查询中,我们通过 LEFT JOINcustomers 表和 orders 表连接起来,然后使用 GROUP BY 按客户名称分组,并使用 COUNTSUM 聚合函数分别计算每个客户的订单数和总金额。

案例 2:查询购买了特定商品的客户信息

假设我们要查询购买了 “Product X” 的客户信息:

SELECT c.customer_name, c.phone
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
WHERE p.product_name = 'Product X';

此查询通过多次连接 customersordersorder_itemsproducts 表,然后使用 WHERE 子句筛选出购买了 “Product X” 的客户信息。

案例 3:查询每个类别商品的销售总额和平均订单数量

SELECT p.category, SUM(oi.quantity * oi.price) AS total_sales, AVG(oi.quantity) AS average_quantity
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY p.category;

这里通过连接 products 表和 order_items 表,使用 GROUP BY 按商品类别分组,利用聚合函数 SUM 计算每个类别的销售总额,AVG 计算平均订单数量。

跨平台与不同开发语言中的 SQLite 查询应用

SQLite 因其轻量级和跨平台特性,在多种开发语言中都得到了广泛应用。以下以 Python 和 Java 为例,介绍如何在不同语言中进行 SQLite 查询操作。

Python 中的 SQLite 查询

在 Python 中,使用 sqlite3 模块来操作 SQLite 数据库。以下是一个简单的示例,展示如何连接数据库、执行查询并获取结果:

import sqlite3

# 连接到 SQLite 数据库
conn = sqlite3.connect('example.db')
cursor = conn.cursor()

# 执行查询
cursor.execute('SELECT * FROM employees')

# 获取所有结果
results = cursor.fetchall()
for row in results:
    print(row)

# 关闭连接
conn.close()

如果要执行带参数的查询,例如查询 age 大于某个值的员工,可以这样写:

import sqlite3

conn = sqlite3.connect('example.db')
cursor = conn.cursor()

age = 30
cursor.execute('SELECT * FROM employees WHERE age >?', (age,))

results = cursor.fetchall()
for row in results:
    print(row)

conn.close()

Java 中的 SQLite 查询

在 Java 中,需要使用 JDBC 来操作 SQLite 数据库。首先要下载 SQLite JDBC 驱动并添加到项目的类路径中。以下是一个简单的示例:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class SQLiteQueryExample {
    public static void main(String[] args) {
        try {
            // 加载 JDBC 驱动
            Class.forName("org.sqlite.JDBC");

            // 连接到 SQLite 数据库
            Connection conn = DriverManager.getConnection("jdbc:sqlite:example.db");

            // 创建语句对象
            Statement statement = conn.createStatement();

            // 执行查询
            ResultSet resultSet = statement.executeQuery("SELECT * FROM employees");

            // 处理结果
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
            }

            // 关闭资源
            resultSet.close();
            statement.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果要执行带参数的查询,例如查询 salary 大于某个值的员工,可以使用 PreparedStatement

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class SQLiteParameterQueryExample {
    public static void main(String[] args) {
        try {
            Class.forName("org.sqlite.JDBC");
            Connection conn = DriverManager.getConnection("jdbc:sqlite:example.db");

            int salary = 5000;
            String query = "SELECT * FROM employees WHERE salary >?";
            PreparedStatement preparedStatement = conn.prepareStatement(query);
            preparedStatement.setInt(1, salary);

            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
            }

            resultSet.close();
            preparedStatement.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

通过以上详细介绍,涵盖了 SQLite 数据库查询操作的各个方面,从基础的查询语句到复杂的连接、子查询,以及在不同开发语言中的应用,希望能帮助读者深入理解和掌握 SQLite 的查询技巧,在实际项目中更好地运用 SQLite 进行数据管理和检索。