Python sqlite3.Connection.create_collation 方法
上次修改时间:2025 年 4 月 15 日
本综合指南探讨了 Python 的 create_collation 方法,该方法允许为 SQLite 数据库定义自定义排序规则序列。
基本定义
排序规则是一组用于比较数据库操作中的文本字符串的规则。 SQLite 使用排序规则进行排序和比较,例如 ORDER BY、GROUP BY 等。
create_collation 方法将 Python 函数注册为自定义排序规则序列。 此函数必须接受两个字符串并返回 -1、0 或 1。
基本排序规则示例
此示例演示如何创建简单的不区分大小写的排序规则序列。
import sqlite3
def case_insensitive_collation(a, b):
a = a.lower()
b = b.lower()
if a < b:
return -1
elif a > b:
return 1
else:
return 0
with sqlite3.connect(':memory:') as conn:
conn.create_collation('NOCASE', case_insensitive_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE words (word TEXT)')
cursor.executemany('INSERT INTO words VALUES (?)',
[('Apple',), ('banana',), ('cherry',)])
cursor.execute('SELECT word FROM words ORDER BY word COLLATE NOCASE')
print([row[0] for row in cursor.fetchall()])
该示例创建一个名为“NOCASE”的不区分大小写的排序规则。 Python 函数在比较之前将字符串转换为小写。
使用 COLLATE NOCASE 排序时,“Apple”、“banana”、“cherry”按不区分大小写的方式排序。 输出将是 ['Apple', 'banana', 'cherry']。
反向排序规则
此示例演示如何创建按相反顺序对字符串进行排序的排序规则。
import sqlite3
def reverse_collation(a, b):
if a < b:
return 1
elif a > b:
return -1
else:
return 0
with sqlite3.connect(':memory:') as conn:
conn.create_collation('REVERSE', reverse_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE items (name TEXT)')
cursor.executemany('INSERT INTO items VALUES (?)',
[('A',), ('B',), ('C',), ('D',)])
cursor.execute('SELECT name FROM items ORDER BY name COLLATE REVERSE')
print([row[0] for row in cursor.fetchall()])
reverse_collation 函数只是反转了正常的比较逻辑。 通常会较早排序的字符串现在排序较晚,反之亦然。
输出将是 ['D', 'C', 'B', 'A'],展示了反向排序顺序。
数字排序规则
此示例演示如何创建对存储为文本的数字进行排序的排序规则。
import sqlite3
def numeric_collation(a, b):
try:
a_num = float(a)
b_num = float(b)
if a_num < b_num:
return -1
elif a_num > b_num:
return 1
else:
return 0
except ValueError:
# Fall back to regular string comparison if not numbers
if a < b:
return -1
elif a > b:
return 1
else:
return 0
with sqlite3.connect(':memory:') as conn:
conn.create_collation('NUMERIC', numeric_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE numbers (value TEXT)')
cursor.executemany('INSERT INTO numbers VALUES (?)',
[('10',), ('2',), ('1',), ('20',)])
cursor.execute('SELECT value FROM numbers ORDER BY value COLLATE NUMERIC')
print([row[0] for row in cursor.fetchall()])
numeric_collation 函数在比较之前将字符串转换为数字。 这确保了“10”在数字上位于“2”之后,而不是按字母顺序排列。
输出将是 ['1', '2', '10', '20'],显示了正确的数字顺序。
区域设置感知的排序规则
此示例演示了尊重特定于区域设置的排序规则的排序规则。
import sqlite3
import locale
def locale_collation(a, b):
return locale.strcoll(a, b)
# Set the locale to the user's default
locale.setlocale(locale.LC_ALL, '')
with sqlite3.connect(':memory:') as conn:
conn.create_collation('LOCALE', locale_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE words (word TEXT)')
words = [('été',), ('eté',), ('étage',), ('étalage',)]
cursor.executemany('INSERT INTO words VALUES (?)', words)
cursor.execute('SELECT word FROM words ORDER BY word COLLATE LOCALE')
print([row[0] for row in cursor.fetchall()])
locale_collation 函数使用 Python 的 locale 模块来执行区域设置感知的字符串比较。 这对于许多语言中正确排序带重音符号的字符非常重要。
输出将根据系统区域设置而异,但会显示法语单词带重音符号的正确的语言特定排序。
自然排序规则
此示例实现了自然排序,其中字符串中的数字按数值而非按字典顺序进行比较。
import sqlite3
import re
def natural_sort_key(s):
return [int(text) if text.isdigit() else text.lower()
for text in re.split('([0-9]+)', s)]
def natural_collation(a, b):
a_key = natural_sort_key(a)
b_key = natural_sort_key(b)
if a_key < b_key:
return -1
elif a_key > b_key:
return 1
else:
return 0
with sqlite3.connect(':memory:') as conn:
conn.create_collation('NATURAL', natural_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE files (name TEXT)')
files = [('file1.txt',), ('file10.txt',), ('file2.txt',), ('file20.txt',)]
cursor.executemany('INSERT INTO files VALUES (?)', files)
cursor.execute('SELECT name FROM files ORDER BY name COLLATE NATURAL')
print([row[0] for row in cursor.fetchall()])
natural_collation 函数将字符串拆分为文本和数字部分,并将数字转换为整数以进行正确的数值比较。
输出将是 ['file1.txt', 'file2.txt', 'file10.txt', 'file20.txt'],显示了正确的自然排序顺序。
不区分变音符号的排序规则
此示例创建一个在比较时忽略变音符号的排序规则。
import sqlite3
import unicodedata
def remove_diacritics(s):
return ''.join(c for c in unicodedata.normalize('NFD', s)
if not unicodedata.combining(c))
def diacritic_insensitive_collation(a, b):
a_simple = remove_diacritics(a)
b_simple = remove_diacritics(b)
if a_simple < b_simple:
return -1
elif a_simple > b_simple:
return 1
else:
return 0
with sqlite3.connect(':memory:') as conn:
conn.create_collation('DIACRITIC_INSENSITIVE', diacritic_insensitive_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE words (word TEXT)')
words = [('café',), ('cafe',), ('résumé',), ('resume',)]
cursor.executemany('INSERT INTO words VALUES (?)', words)
cursor.execute('SELECT word FROM words ORDER BY word COLLATE DIACRITIC_INSENSITIVE')
print([row[0] for row in cursor.fetchall()])
排序规则在使用 Unicode 规范化进行比较之前删除变音符号。 这使得“café”和“cafe”比较时相等。
输出将根据其基本字符将带和不带变音符号的单词组合在一起。
自定义加权排序规则
此示例演示了将自定义权重应用于某些字符的排序规则。
import sqlite3
def weighted_collation(a, b):
# Custom weights for certain characters
weights = {'@': 0, '#': 1, '$': 2}
def get_weight(c):
return weights.get(c, ord(c))
for a_char, b_char in zip(a, b):
a_weight = get_weight(a_char)
b_weight = get_weight(b_char)
if a_weight < b_weight:
return -1
elif a_weight > b_weight:
return 1
# If all compared characters were equal, compare lengths
if len(a) < len(b):
return -1
elif len(a) > len(b):
return 1
else:
return 0
with sqlite3.connect(':memory:') as conn:
conn.create_collation('WEIGHTED', weighted_collation)
cursor = conn.cursor()
cursor.execute('CREATE TABLE symbols (value TEXT)')
symbols = [('apple',), ('@pple',), ('#pple',), ('$pple',)]
cursor.executemany('INSERT INTO symbols VALUES (?)', symbols)
cursor.execute('SELECT value FROM symbols ORDER BY value COLLATE WEIGHTED')
print([row[0] for row in cursor.fetchall()])
weighted_collation 函数将自定义排序权重应用于特定符号(@、#、$),同时保持其他字符的正常排序。
输出将是 ['@pple', '#pple', '$pple', 'apple'],显示了自定义符号排序,然后是常规的字母排序。
最佳实践
- 保持排序规则函数简单:复杂的逻辑会降低查询速度
- 处理边缘情况:考虑 None 值和不同的类型
- 使用 Unicode 规范化:为了保持文本比较的一致性
- 彻底测试:验证各种输入的行为
- 记录自定义排序规则:解释其目的和行为
资料来源
作者
列出所有 Python 教程。