Python SQLite:`WHERE` 子句深度解析
目录
- 引言:精准筛选数据的利器——
WHERE子句 WHERE子句基础- 2.1 语法结构
- 2.2 与
SELECT语句的结合
WHERE子句中的运算符- 3.1 比较运算符 (
=,!=,<,>,<=,>=) - 3.2 逻辑运算符 (
AND,OR,NOT) - 3.3 范围运算符 (
BETWEEN) - 3.4 集合运算符 (
IN,NOT IN) - 3.5 模式匹配运算符 (
LIKE,GLOB)- 3.5.1
LIKE通配符 (%,_) - 3.5.2
GLOB通配符 (*,?,[]) - 3.5.3
LIKE与GLOB的区别
- 3.5.1
- 3.6 空值判断 (
IS NULL,IS NOT NULL) - 3.7 存在性判断 (
EXISTS,NOT EXISTS) (与子查询结合) - 3.8 大小写敏感性 (
COLLATE NOCASE)
- 3.1 比较运算符 (
WHERE子句与其他 SQL 子句的结合- 4.1
WHERE与ORDER BY - 4.2
WHERE与LIMIT/OFFSET - 4.3
WHERE与JOIN
- 4.1
- 在 Python
sqlite3中使用WHERE子句- 5.1 参数绑定:防止 SQL 注入的核心
- 5.1.1 位置参数 (
?) - 5.1.2 命名参数 (
:name)
- 5.1.1 位置参数 (
- 5.2 执行查询与获取结果
- 5.3 处理 Python 数据类型
- 5.1 参数绑定:防止 SQL 注入的核心
- 性能优化:索引与
WHERE- 6.1 索引的重要性
- 6.2 何时创建索引
- 错误处理
- 7.1
sqlite3.OperationalError
- 7.1
- 最佳实践与注意事项
- 8.1 再次强调:永远使用参数绑定!
- 8.2 使用
with语句管理资源 - 理解
NULL值的特殊性 - 小心使用
LIKE和GLOB(性能影响) - 优化查询性能:索引、特定列选择
- 外键约束的启用
- 综合代码示例
- 9.1 数据库结构和数据准备
- 9.2 各种
WHERE子句查询示例
- 总结
1. 引言:精准筛选数据的利器——WHERE 子句
在上一篇深度解析中,我们学习了如何使用 SELECT 语句从数据库中检索数据。然而,SELECT 语句常常会返回表中所有的行,这在大多数实际应用中并非所需。为了从海量数据中精确地找出我们关注的特定记录,SQL 提供了强大的 WHERE 子句。
WHERE 子句允许您根据一个或多个条件过滤查询结果,确保只有满足这些条件的行才会被返回。它是 SQL 查询的核心组成部分之一,对于数据检索的效率和准确性至关重要。
本指南将详细讲解 WHERE 子句的各种用法,包括其支持的运算符、与其他 SQL 子句的结合,以及如何在 Python 的 sqlite3 模块中安全高效地应用它。
2. WHERE 子句基础
2.1 语法结构
WHERE 子句紧跟在 FROM 子句之后(或 JOIN 子句之后),它包含一个或多个布尔表达式,这些表达式评估为 TRUE、FALSE 或 NULL。只有评估为 TRUE 的行才会被包含在结果集中。
SELECT column1, column2, ...
FROM table_name
WHERE condition;
condition: 一个或多个布尔表达式,可以包含列名、字面值、函数、运算符等。
2.2 与 SELECT 语句的结合
WHERE 子句可以与 SELECT 语句的任何形式结合使用,无论是选择所有列 (*) 还是特定列。
示例:
-- 选择所有客户,但只筛选出名为 'Alice' 的客户
SELECT *
FROM customers
WHERE first_name = 'Alice';
3. WHERE 子句中的运算符
WHERE 子句支持多种运算符来构建复杂的筛选条件。
3.1 比较运算符 (=, !=, <, >, <=, >=)
用于比较两个值。
=: 等于!=(或<>): 不等于<: 小于>: 大于<=: 小于等于>=: 大于等于
示例:
SELECT name, price FROM products WHERE price >= 100;
SELECT first_name, last_name FROM customers WHERE registration_date < '2023-03-01';
SELECT order_id, total_amount FROM orders WHERE is_completed != 1; -- is_completed 是 BOOLEAN,存储为 0 或 1
3.2 逻辑运算符 (AND, OR, NOT)
用于组合多个条件。
AND: 逻辑与,只有当所有条件都为TRUE时,整个条件才为TRUE。OR: 逻辑或,只要有一个条件为TRUE,整个条件就为TRUE。NOT: 逻辑非,反转条件的布尔值。
示例:
SELECT * FROM products WHERE stock > 50 AND price < 500;
SELECT * FROM customers WHERE first_name = 'Alice' OR last_name = 'Johnson';
SELECT * FROM orders WHERE NOT is_completed AND total_amount > 100; -- 未完成且金额大于 100 的订单
优先级: NOT > AND > OR。可以使用括号 () 来明确指定运算顺序。
3.3 范围运算符 (BETWEEN)
用于检查一个值是否在两个值之间(包含边界值)。
SELECT name, price FROM products WHERE price BETWEEN 50.00 AND 300.00; -- 价格在 50.00 到 300.00 之间
等价于:price >= 50.00 AND price <= 300.00。
3.4 集合运算符 (IN, NOT IN)
用于检查一个值是否在一组给定值中。
SELECT first_name, last_name FROM customers WHERE first_name IN ('Alice', 'David', 'Eve');
SELECT name FROM products WHERE name NOT IN ('Laptop', 'Monitor');
3.5 模式匹配运算符 (LIKE, GLOB)
用于字符串的模糊匹配。
3.5.1 LIKE 通配符 (%, _)
%: 匹配零个、一个或多个任意字符。_: 匹配任何单个字符。
SELECT email FROM customers WHERE email LIKE '%@example.com'; -- 查找所有以 @example.com 结尾的邮箱
SELECT name FROM products WHERE name LIKE 'M_u%'; -- 匹配 'Mouse', 'Mount' 等
3.5.2 GLOB 通配符 (*, ?, [])
GLOB 提供 Unix 文件名匹配语法。它通常区分大小写(除非数据库默认设置或使用 COLLATE NOCASE),而 LIKE 默认不区分大小写(取决于数据库配置,SQLite 默认不区分)。
*: 匹配零个或多个任意字符 (与LIKE的%相似)。?: 匹配任何单个字符 (与LIKE的_相似)。[]: 匹配方括号内的任何单个字符。[^]: 匹配不在方括号内的任何单个字符。
SELECT first_name FROM customers WHERE first_name GLOB 'A*'; -- 查找以 'A' 开头的所有名字
SELECT name FROM products WHERE name GLOB 'M?nitor'; -- 匹配 'Monitor', 'Manitor' 等
SELECT name FROM products WHERE name GLOB '[KL]*'; -- 匹配以 'K' 或 'L' 开头的产品
3.5.3 LIKE 与 GLOB 的区别
- 通配符:
LIKE使用%和_;GLOB使用*和?。 - 大小写敏感性:
LIKE默认不区分大小写(但在某些配置下可能区分);GLOB默认区分大小写。如果需要GLOB不区分大小写,可以使用COLLATE NOCASE。
3.6 空值判断 (IS NULL, IS NOT NULL)
这是检查列是否为 NULL 的唯一正确方式。您不能使用 = NULL 或 != NULL,因为 NULL 表示“未知”,任何与 NULL 的比较都会得到 NULL (在布尔上下文中被视为 FALSE)。
SELECT customer_id, email FROM customers WHERE email IS NULL; -- 查找邮箱为空的客户
SELECT customer_id, email FROM customers WHERE email IS NOT NULL; -- 查找邮箱不为空的客户
3.7 存在性判断 (EXISTS, NOT EXISTS) (与子查询结合)
EXISTS 运算符与子查询一起使用,用于测试子查询是否返回任何行。如果子查询返回至少一行,EXISTS 返回 TRUE;否则返回 FALSE。
-- 查找下过订单的客户
SELECT first_name, last_name FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);
-- 查找从未下过订单的客户
SELECT first_name, last_name FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);
3.8 大小写敏感性 (COLLATE NOCASE)
SQLite 默认的字符串比较规则是大小写不敏感的,但可以通过 COLLATE 关键字来指定排序规则。NOCASE 表示不区分大小写,BINARY 表示区分大小写。
SELECT first_name FROM customers WHERE first_name = 'alice' COLLATE NOCASE; -- 强制不区分大小写比较
SELECT first_name FROM customers WHERE first_name GLOB 'alice' COLLATE NOCASE; -- 强制 GLOB 不区分大小写
4. WHERE 子句与其他 SQL 子句的结合
WHERE 子句通常与其他 SQL 子句一起使用,以构建更复杂和精确的查询。
4.1 WHERE 与 ORDER BY
WHERE 子句过滤数据,然后 ORDER BY 子句对过滤后的结果进行排序。
SELECT name, price FROM products
WHERE stock > 100
ORDER BY price DESC;
4.2 WHERE 与 LIMIT/OFFSET
WHERE 子句过滤数据,然后 LIMIT 和 OFFSET 子句限制返回的行数和起始位置。
SELECT first_name, last_name FROM customers
WHERE registration_date > '2023-02-01'
ORDER BY registration_date ASC
LIMIT 3 OFFSET 0; -- 查找 2023 年 2 月 1 日后注册的前 3 位客户
4.3 WHERE 与 JOIN
当使用 JOIN 连接多个表时,WHERE 子句可以对连接后的结果集进行过滤。
SELECT c.first_name, o.order_date, o.total_amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE o.total_amount > 500 AND o.is_completed = 0; -- 查找金额大于 500 且未完成的订单及其客户信息
5. 在 Python sqlite3 中使用 WHERE 子句
在 Python 中执行带 WHERE 子句的查询,关键在于使用参数绑定。
5.1 参数绑定:防止 SQL 注入的核心
重要提示: 绝不将用户输入或其他动态值直接拼接到 SQL 查询字符串中。这会使您的应用程序容易受到 SQL 注入攻击。相反,请使用参数绑定。sqlite3 模块会自动处理值的转义和类型转换。
5.1.1 位置参数 (?)
使用问号 ? 作为占位符,将要替换的值作为元组传递给 cursor.execute() 方法的第二个参数。
customer_email = "alice@example.com"
cursor.execute("SELECT * FROM customers WHERE email = ?", (customer_email,)) # 注意:即使只有一个参数,也必须是元组
alice_data = cursor.fetchone()
5.1.2 命名参数 (:name)
使用 :param_name 作为占位符,将值作为字典传递。这种方式在参数多时可读性更高。
min_stock = 50
max_price = 100.0
cursor.execute("SELECT name, stock, price FROM products WHERE stock > :min_s AND price < :max_p",
{'min_s': min_stock, 'max_p': max_price})
products_data = cursor.fetchall()
5.2 执行查询与获取结果
执行查询的流程与普通 SELECT 相同:
cursor.execute(sql_query, parameters): 执行查询。cursor.fetchone(),cursor.fetchmany(size),cursor.fetchall()或直接迭代cursor: 获取结果。
5.3 处理 Python 数据类型
sqlite3 模块会自动将 Python 基本数据类型(str, int, float, bytes, None, bool, datetime.date, datetime.datetime)转换为 SQLite 兼容的格式,并在检索时(如果配置了 detect_types)将其转换回 Python 对象。这使得您可以在 WHERE 子句中直接使用 Python 对象进行比较。
示例:
# 查询特定注册日期后的客户 (datetime.date 对象)
target_date = datetime.date(2023, 3, 1)
cursor.execute("SELECT first_name, last_name, registration_date FROM customers WHERE registration_date >= ?", (target_date,))
recent_customers = cursor.fetchall()
# 查询已完成的订单 (bool 对象)
is_completed_status = True
cursor.execute("SELECT order_id, total_amount, is_completed FROM orders WHERE is_completed = ?", (is_completed_status,))
completed_orders = cursor.fetchall()
6. 性能优化:索引与 WHERE
6.1 索引的重要性
当 WHERE 子句对表进行过滤时,数据库通常会扫描整个表来查找匹配的行(全表扫描)。对于大型表,这会非常慢。索引可以极大地加速查询,特别是那些在 WHERE 子句中使用的列。索引就像一本书的目录,让数据库可以直接跳转到相关数据,而不是从头到尾翻阅。
6.2 何时创建索引
- 经常出现在
WHERE子句中的列。 - 用于
JOIN条件的列。 - 用于
ORDER BY子句的列。 PRIMARY KEY和UNIQUE约束的列会自动创建索引。
然而,索引会增加写入操作(INSERT, UPDATE, DELETE)的开销,因为每次数据更改时,索引也需要更新。因此,需要权衡读取性能和写入性能。
示例 (创建索引):
CREATE INDEX idx_customers_email ON customers (email);
CREATE INDEX idx_orders_customer_id ON orders (customer_id);
7. 错误处理
在使用 WHERE 子句执行查询时,最常见的错误是 sqlite3.OperationalError。
7.1 sqlite3.OperationalError
这通常表示 SQL 语法错误、引用的表或列不存在、数据库文件被锁定或损坏等问题。
try:
# 尝试查询一个不存在的列
cursor.execute("SELECT non_existent_column FROM customers WHERE customer_id = 1")
results = cursor.fetchall()
except sqlite3.OperationalError as e:
print(f"\n捕获到 OperationalError: {e}")
print("查询失败,请检查列名和表名是否正确。")
8. 最佳实践与注意事项
8.1 再次强调:永远使用参数绑定!
这是最重要的一点。任何时候,只要您在 SQL 查询中包含外部或动态值,就必须使用参数绑定。不要拼接字符串!这不仅防止了 SQL 注入,还处理了复杂的类型转换和转义问题。
8.2 使用 with 语句管理资源
这确保了数据库连接和游标的正确关闭,即使在发生异常时也能自动回滚事务(对于修改数据的操作)。
8.3 理解 NULL 值的特殊性
记住 NULL 永远不等于任何东西(包括另一个 NULL)。因此,总是使用 IS NULL 或 IS NOT NULL 来检查 NULL 值。
8.4 小心使用 LIKE 和 GLOB (性能影响)
- 前导通配符 (
%term或*term) 会阻止数据库使用索引,因为它需要扫描所有可能的匹配。如果可能,尽量避免使用前导通配符,或在设计时考虑全文搜索方案。 COLLATE NOCASE可能会在某些情况下影响性能,因为它需要在比较时进行额外的处理。
8.5 优化查询性能:索引、特定列选择
- 为
WHERE子句中频繁使用的列创建索引。 - 只选择您需要的列,而不是
SELECT *。 - 对于大量数据,考虑分页 (
LIMIT/OFFSET)。
8.6 外键约束的启用
虽然 WHERE 子句是关于数据过滤而非数据完整性,但在进行 JOIN 操作时,如果外键约束没有启用,您可能会得到不一致的数据或查询结果不符合预期。因此,始终在每个连接中启用 PRAGMA foreign_keys = ON; 是一个好的习惯。
8.7 ALTER TABLE 限制与常见变通方案
(这是针对表结构修改的提醒,与 WHERE 查询本身无关,但作为整个数据库操作的通用最佳实践值得再次提及)SQLite 对 ALTER TABLE 的支持相对有限。例如,它不能直接删除列,也不能直接修改列的数据类型或约束(除了少数例外)。对于更复杂的模式更改(例如,删除列、修改列类型、重新排序列),常见的变通方法是:
- 创建具有所需新结构的新表。
- 将旧表中的数据复制到新表(只复制兼容的列)。
- 删除旧表。
- 将新表重命名为旧表的名称。
理解这些限制对于规划数据库模式演进至关重要。
9. 综合代码示例
此示例将基于之前创建的数据库和数据,演示各种 WHERE 子句的实际应用。
import sqlite3
import os
import datetime
db_name = 'comprehensive_where_db.db'
if os.path.exists(db_name):
os.remove(db_name)
with sqlite3.connect(db_name, detect_types=sqlite3.PARSE_DECLTYPES) as conn:
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("PRAGMA foreign_keys = ON;")
# --- 准备数据 (与前几篇深度解析的设置一致) ---
cursor.execute('''
CREATE TABLE IF NOT EXISTS customers (
customer_id INTEGER PRIMARY KEY AUTOINCREMENT,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT UNIQUE, -- 允许 email 为 NULL,用于演示 IS NULL
registration_date DATE DEFAULT CURRENT_DATE
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
product_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
price REAL CHECK(price > 0) DEFAULT 0.0,
stock INTEGER DEFAULT 0 CHECK(stock >= 0)
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS orders (
order_id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL,
order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
total_amount REAL,
is_completed BOOLEAN DEFAULT FALSE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE CASCADE
)
''')
# 插入一些示例数据
cursor.executemany("INSERT INTO customers (first_name, last_name, email, registration_date) VALUES (?, ?, ?, ?)", [
("Alice", "Smith", "alice@example.com", datetime.date(2023, 1, 10)),
("Bob", "Johnson", "bob@example.com", datetime.date(2023, 1, 15)),
("Charlie", "Brown", "charlie@example.com", datetime.date(2023, 2, 20)),
("David", "Lee", "david@example.com", datetime.date(2023, 3, 5)),
("Eve", "Wang", "eve@example.com", datetime.date(2023, 3, 10)),
("Frank", "Green", None, datetime.date(2023, 4, 1)) # Frank 的 email 为 NULL
])
cursor.executemany("INSERT INTO products (name, price, stock) VALUES (?, ?, ?)", [
("Laptop", 1200.50, 20),
("Mouse", 25.00, 150),
("Keyboard", 75.99, 80),
("Monitor", 300.00, 30),
("Webcam", 49.99, 100),
("Desk Lamp", 35.00, 60),
("USB Hub", 15.00, 200)
])
cursor.execute("SELECT customer_id FROM customers WHERE email = 'alice@example.com'")
alice_id = cursor.fetchone()['customer_id']
cursor.execute("SELECT customer_id FROM customers WHERE email = 'bob@example.com'")
bob_id = cursor.fetchone()['customer_id']
cursor.execute("SELECT customer_id FROM customers WHERE email = 'charlie@example.com'")
charlie_id = cursor.fetchone()['customer_id']
cursor.execute("SELECT customer_id FROM customers WHERE email IS NULL")
frank_id = cursor.fetchone()['customer_id'] # 获取 Frank 的 ID
cursor.executemany("INSERT INTO orders (customer_id, order_date, total_amount, is_completed) VALUES (?, ?, ?, ?)", [
(alice_id, datetime.datetime(2023, 1, 20, 10, 30), 1250.00, False),
(bob_id, datetime.datetime(2023, 3, 1, 14, 0), 50.00, True),
(alice_id, datetime.datetime(2023, 2, 5, 9, 0), 200.00, True),
(charlie_id, datetime.datetime(2023, 4, 10, 11, 45), 800.00, False),
(bob_id, datetime.datetime(2023, 3, 10, 16, 20), 15.00, True),
(alice_id, datetime.datetime(2023, 4, 2, 13, 0), 300.00, False),
(frank_id, datetime.datetime(2023, 4, 5, 10, 0), 99.99, False) # Frank 的订单
])
print("数据库和初始数据已准备好。\n")
# --- 演示各种 WHERE 子句查询 ---
print("--- 1. 比较运算符 (=, <) ---")
# 查询价格大于等于 100 的产品
min_price_param = 100.0
cursor.execute("SELECT name, price FROM products WHERE price >= ?", (min_price_param,))
print(f" 价格 >= ${min_price_param} 的产品:")
for row in cursor.fetchall():
print(f" {row['name']} (价格: ${row['price']})")
print("\n--- 2. 逻辑运算符 (AND, OR) ---")
# 查询库存大于 50 且价格小于 200 的产品
min_stock_param = 50
max_price_param = 200.0
cursor.execute("SELECT name, stock, price FROM products WHERE stock > ? AND price < ?", (min_stock_param, max_price_param))
print(f" 库存 > {min_stock_param} 且价格 < ${max_price_param} 的产品:")
for row in cursor.fetchall():
print(f" {row['name']} (库存: {row['stock']}, 价格: ${row['price']})")
print("\n--- 3. 范围运算符 (BETWEEN) ---")
# 查询总金额在 50 到 500 之间的订单
min_amount_param = 50.0
max_amount_param = 500.0
cursor.execute("SELECT order_id, total_amount FROM orders WHERE total_amount BETWEEN ? AND ?", (min_amount_param, max_amount_param))
print(f" 总金额在 ${min_amount_param} 到 ${max_amount_param} 之间的订单:")
for row in cursor.fetchall():
print(f" 订单ID: {row['order_id']}, 总金额: ${row['total_amount']}")
print("\n--- 4. 集合运算符 (IN, NOT IN) ---")
# 查询 Alice 和 Bob 的订单
customer_ids_param = (alice_id, bob_id)
cursor.execute("SELECT order_id, customer_id, total_amount FROM orders WHERE customer_id IN (?, ?)", customer_ids_param)
print(f" Alice (ID:{alice_id}) 和 Bob (ID:{bob_id}) 的订单:")
for row in cursor.fetchall():
print(f" 订单ID: {row['order_id']}, 客户ID: {row['customer_id']}, 金额: ${row['total_amount']}")
print("\n--- 5. 模式匹配 (LIKE, GLOB) ---")
# 使用 LIKE 查询以 'M' 开头的产品
like_pattern = 'M%'
cursor.execute("SELECT name FROM products WHERE name LIKE ?", (like_pattern,))
print(f" 名称以 '{like_pattern}' 开头的产品 (LIKE):")
for row in cursor.fetchall():
print(f" {row['name']}")
# 使用 GLOB 查询以 'M' 开头的产品 (GLOB 默认区分大小写)
glob_pattern = 'M*'
cursor.execute("SELECT name FROM products WHERE name GLOB ?", (glob_pattern,))
print(f" 名称以 '{glob_pattern}' 开头的产品 (GLOB):")
for row in cursor.fetchall():
print(f" {row['name']}")
# 使用 GLOB + COLLATE NOCASE 查询以 'm' 开头的产品 (不区分大小写)
glob_pattern_nocase = 'm*'
cursor.execute("SELECT name FROM products WHERE name GLOB ? COLLATE NOCASE", (glob_pattern_nocase,))
print(f" 名称以 '{glob_pattern_nocase}' 开头的产品 (GLOB COLLATE NOCASE):")
for row in cursor.fetchall():
print(f" {row['name']}")
print("\n--- 6. 空值判断 (IS NULL, IS NOT NULL) ---")
cursor.execute("SELECT first_name, last_name, email FROM customers WHERE email IS NULL")
print(" 邮箱为 NULL 的客户:")
for row in cursor.fetchall():
print(f" {row['first_name']} {row['last_name']}")
cursor.execute("SELECT first_name, last_name, email FROM customers WHERE email IS NOT NULL")
print("\n 邮箱不为 NULL 的客户:")
for row in cursor.fetchall():
print(f" {row['first_name']} {row['last_name']} ({row['email']})")
print("\n--- 7. 存在性判断 (EXISTS) ---")
cursor.execute('''
SELECT c.first_name, c.last_name
FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id AND o.total_amount > ?)
''', (500,))
print(" 下过金额大于 $500 订单的客户:")
for row in cursor.fetchall():
print(f" {row['first_name']} {row['last_name']}")
print("\n--- 8. 结合多个子句 (WHERE, ORDER BY, LIMIT) ---")
cursor.execute('''
SELECT first_name, last_name, registration_date
FROM customers
WHERE registration_date >= ?
ORDER BY registration_date DESC
LIMIT ?
''', (datetime.date(2023, 2, 1), 3))
print(" 2023年2月1日后注册,按注册日期降序排列的前3位客户:")
for row in cursor.fetchall():
print(f" {row['first_name']} {row['last_name']} (注册日期: {row['registration_date']})")
print("\n--- 9. 结合 JOIN 和 WHERE ---")
cursor.execute('''
SELECT c.first_name, c.last_name, o.order_id, o.total_amount, o.is_completed
FROM customers AS c
INNER JOIN orders AS o ON c.customer_id = o.customer_id
WHERE c.first_name = ? AND o.is_completed = ?
''', ('Alice', False))
print(" Alice 未完成的订单:")
for row in cursor.fetchall():
print(f" 订单ID: {row['order_id']}, 总金额: ${row['total_amount']}, 完成: {row['is_completed']}")
print(f"\n所有 `WHERE` 子句演示完成,数据库 '{db_name}' 已更新。")
10. 总结
为您详细介绍了 Python SQLite 中 WHERE 子句的各个方面。
核心要点回顾:
WHERE子句是 SQL 查询中必不可少的部分,用于筛选满足特定条件的行。- 掌握了各种
WHERE运算符,包括比较 (=,!=,<,>), 逻辑 (AND,OR,NOT), 范围 (BETWEEN), 集合 (IN,NOT IN), 模式匹配 (LIKE%_,GLOB*?[]), 空值判断 (IS NULL,IS NOT NULL) 和存在性判断 (EXISTS,NOT EXISTS)。 - 理解
LIKE和GLOB在通配符和大小写敏感性上的区别,并学会使用COLLATE NOCASE。 WHERE子句可以与ORDER BY,LIMIT/OFFSET,JOIN等子句结合,构建强大的查询。- 在 Python 中,始终使用参数绑定 (
?或:name) 来传递WHERE子句中的值,这是防止 SQL 注入和确保正确数据类型转换的关键。 - 了解索引在优化带
WHERE子句的查询性能中的重要性。 - 遵循最佳实践,如使用
with语句管理连接、只选择必需的列,并注意NULL值的特殊处理。
通过这些全面而深入的知识,您将能够精确地控制从 SQLite 数据库中检索的数据,并构建更安全、高效和健壮的 Python 数据库应用程序。
清理测试文件 (为确保后续测试环境干净)
import os
files_to_clean = [
'comprehensive_where_db.db'
]
for f in files_to_clean:
if os.path.exists(f):
os.remove(f)
print("\n所有测试数据库文件已清理。")
更多推荐

所有评论(0)