Python sqlite3.Connection.executescript 方法
上次修改时间:2025 年 4 月 15 日
本综合指南探讨了 Python 的 sqlite3.Connection.executescript 方法,该方法一次执行多个 SQL 语句。我们将介绍基本用法、事务行为和实际示例。
基本定义
executescript 方法在单个调用中执行 SQL 语句的脚本。 它是 sqlite3.Connection 类的一部分,对批量操作非常有用。
主要特点:它在一个事务中执行所有语句,接受带有 SQL 命令的字符串参数,并且不返回任何结果。 它非常适合模式设置或迁移。
基本 executescript 示例
这是一个简单的例子,演示了如何使用 executescript 来创建表并在一个操作中插入数据。
import sqlite3
with sqlite3.connect('test.db') as conn:
script = """
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
);
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
amount REAL,
FOREIGN KEY(user_id) REFERENCES users(id)
);
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');
"""
conn.executescript(script)
此示例创建一个单个脚本创建两个相关的表并插入示例数据。 with 语句确保正确的连接清理。
所有语句都作为单个事务的一部分执行。 如果任何语句失败,则整个事务将自动回滚。
事务行为
此示例演示了当脚本中发生错误时 executescript 的事务行为。
import sqlite3
with sqlite3.connect('transactions.db') as conn:
try:
script = """
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY,
name TEXT,
balance REAL
);
INSERT INTO accounts (name, balance) VALUES ('Alice', 1000);
INSERT INTO accounts (name, balance) VALUES ('Bob', 500);
-- This will cause an error (table doesn't exist)
INSERT INTO transactions (account_id, amount) VALUES (1, -100);
"""
conn.executescript(script)
except sqlite3.Error as e:
print("Error executing script:", e)
# Verify no partial changes were committed
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM accounts")
print("Accounts count:", cursor.fetchone()[0]) # Outputs 0
该脚本包含一个错误(插入到不存在的表中)。 整个事务回滚,数据库保持不变。
这种原子行为可确保在执行多个相关语句时的数据一致性。
模式迁移脚本
executescript 非常适合数据库模式迁移。 此示例显示了版本升级脚本。
import sqlite3
with sqlite3.connect('app.db') as conn:
migration_script = """
-- Add new columns to existing table
ALTER TABLE users ADD COLUMN last_login TEXT;
ALTER TABLE users ADD COLUMN status TEXT DEFAULT 'active';
-- Create new tables for features
CREATE TABLE IF NOT EXISTS user_preferences (
user_id INTEGER PRIMARY KEY,
theme TEXT DEFAULT 'light',
notifications INTEGER DEFAULT 1,
FOREIGN KEY(user_id) REFERENCES users(id)
);
-- Backfill existing data
UPDATE users SET status = 'active' WHERE status IS NULL;
"""
conn.executescript(migration_script)
此脚本以原子方式执行多个模式更改。 它添加列,创建一个新表并回填数据。
使用 executescript 可确保所有更改一起成功或失败,从而防止部分迁移。
从外部文件加载 SQL
此示例显示了如何从外部文件加载 SQL 并使用 executescript 执行它。
import sqlite3
def load_and_execute_sql(db_file, sql_file):
with sqlite3.connect(db_file) as conn:
with open(sql_file, 'r') as f:
sql_script = f.read()
conn.executescript(sql_script)
# Execute schema.sql file against test.db
load_and_execute_sql('test.db', 'schema.sql')
该函数从文件读取 SQL 并针对数据库执行它。 此模式对于部署脚本很有用。
应为生产用途添加错误处理,以处理文件读取和 SQL 执行错误。
与参数化查询结合使用
虽然 executescript 不直接支持参数,但您可以将其与常规执行结合使用以进行混合操作。
import sqlite3
with sqlite3.connect('inventory.db') as conn:
# Schema setup with executescript
conn.executescript("""
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT,
price REAL,
stock INTEGER
);
CREATE TABLE IF NOT EXISTS categories (
id INTEGER PRIMARY KEY,
name TEXT
);
""")
# Parameterized inserts with execute
cursor = conn.cursor()
products = [
('Laptop', 999.99, 10),
('Phone', 699.99, 25),
('Tablet', 399.99, 15)
]
cursor.executemany("INSERT INTO products (name, price, stock) VALUES (?, ?, ?)", products)
此示例使用 executescript 进行模式创建,使用常规 execute 进行参数化插入。
该组合提供了脚本执行的便利性和参数化查询的安全性。
性能注意事项
此示例演示了 executescript 如何提高批量操作的性能。
import sqlite3
import time
def time_operations():
with sqlite3.connect('perf_test.db') as conn:
conn.execute("DROP TABLE IF EXISTS test_data")
conn.execute("CREATE TABLE test_data (id INTEGER, value TEXT)")
# Method 1: Individual executes
start = time.time()
cursor = conn.cursor()
for i in range(1000):
cursor.execute(f"INSERT INTO test_data VALUES ({i}, 'test{i}')")
conn.commit()
print(f"Individual executes: {time.time() - start:.3f} seconds")
# Method 2: executescript
conn.execute("DROP TABLE test_data")
conn.execute("CREATE TABLE test_data (id INTEGER, value TEXT)")
start = time.time()
script = "\n".join(f"INSERT INTO test_data VALUES ({i}, 'test{i}');"
for i in range(1000))
conn.executescript(script)
print(f"executescript: {time.time() - start:.3f} seconds")
time_operations()
该示例比较了单个插入与单个 executescript 调用。 对于批量操作,脚本方法通常更快。
但是,对于非常大的脚本,应考虑内存使用情况和 SQLite 的 SQL 长度限制。
复杂数据库初始化
此示例显示了一个完整的数据库初始化脚本,其中包含视图、索引和示例数据。
import sqlite3
def initialize_database(db_file):
with sqlite3.connect(db_file) as conn:
init_script = """
PRAGMA foreign_keys = ON;
PRAGMA journal_mode = WAL;
-- Main tables
CREATE TABLE IF NOT EXISTS customers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
amount REAL NOT NULL,
status TEXT DEFAULT 'pending',
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(customer_id) REFERENCES customers(id)
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_orders_customer ON orders(customer_id);
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status);
-- Views
CREATE VIEW IF NOT EXISTS customer_totals AS
SELECT c.id, c.name, SUM(o.amount) as total_spent
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
GROUP BY c.id;
-- Sample data
INSERT INTO customers (name, email) VALUES
('John Doe', 'john@example.com'),
('Jane Smith', 'jane@example.com');
INSERT INTO orders (customer_id, amount) VALUES
(1, 99.99),
(1, 49.99),
(2, 149.99);
"""
conn.executescript(init_script)
initialize_database('ecommerce.db')
此综合初始化脚本使用表、索引、视图和示例数据设置完整的数据库模式。
使用 executescript 可确保原子地创建所有组件,并且 PRAGMA 语句在模式创建之前配置数据库行为。
最佳实践
- 用于模式更改: 非常适合迁移和初始设置
- 处理错误: 包装在 try-except 中以进行正确的错误处理
- 结合使用方法: 需要时与参数化查询混合使用
- 考虑大小限制: SQLite 具有 SQL 长度限制(1,000,000 字节)
- 测试脚本: 首先在开发中验证复杂脚本
资料来源
作者
列出所有 Python 教程。