На этом шаге мы рассмотрим использование метода create_function().
Как уже говорилось на 192 шаге, сравнение строк и поиск с помощью оператора LIKE для русских букв производится с учетом регистра символов. Поэтому следующие выражения вернут значение 0:
>>> cur.execute("SELECT 'строка' = 'Строка'") <sqlite3.Cursor object at 0x02426DA0> >>> print(cur.fetchone()[0]) # Результат: 0 (не равно) 0 >>> cur.execute("SELECT 'строка' LIKE 'Строка'") <sqlite3.Cursor object at 0x02426DA0> >>> print(cur.fetchone()[0]) # Результат: 0 (не равно) 0
Одним из вариантов решения проблемы является преобразование символов обеих строк к верхнему или нижнему регистру. Но встроенные функции SQLite UPPER () и LOWER () с русскими буквами также работают некорректно. Модуль sqlite3 позволяет создать пользовательскую функцию и связать ее с названием функции в SQL-запросе. Таким образом, можно создать пользовательскую функцию преобразования регистра символов, а затем указать связанное с ней имя в SQL-запросе.
Связать название функции в SQL-запросе с пользовательской функцией в программе позволяет метод create_function() объекта соединения. Формат метода:
create_function(<Название функции в SQL-запросе в виде строки>, <Количество параметров>, <Ссылка на функцию>)
В первом параметре в виде строки указывается название функции, которое будет использоваться в SQL-командах. Количество параметров, принимаемых функцией, задается во втором параметре, причем параметры могут быть любого типа. Если функция принимает строку, то ее типом данных будет str. В третьем параметре указывается ссылка на пользовательскую функцию в программе. Для примера произведем поиск рубрики без учета регистра символов:
# -*- coding: utf-8 -*- import sqlite3 # Пользовательская функция изменения регистра def myfunc(s): return s.lower() con = sqlite3.connect("catalog.db") # Связываем имя "mylower" с функцией myfunc() con.create_function("mylower", 1, myfunc) cur = con.cursor() string = "%МуЗЫка%" # Строка для поиска # Поиск без учета регистра символов sql = """SELECT * FROM rubr WHERE mylower(name_rubr) LIKE ?""" cur.execute(sql,(string.lower(),)) print(cur.fetchone()[1]) # Результат: Музыка cur.close() con.close() input()
Результат работы приложения:
Музыка
В этом примере предполагается, что значение переменной string получено от пользователя. Обратите внимание на то, что строку для поиска в метод execute () мы передаем в нижнем регистре. Если этого не сделать и указать преобразование в SQL-запросе, то лишнее преобразование регистра будет производиться при каждом сравнении.
Метод create_function() используется не только для создания функции изменения регистра символов, но и для других целей. Например, в SQLite нет специального типа данных для хранения даты и времени. При этом дату и время можно хранить разными способами - например, в числовом поле как количество секунд, прошедших с начала эпохи. Для преобразования количества секунд в другой формат следует создать пользовательскую функцию форматирования:
# -*- coding: utf-8 -*- import sqlite3 import time def myfunc(d): return time.strftime("%d.%m.%Y", time.localtime(d)) con = sqlite3.connect(":memory:") # Связываем имя "mytime" с функцией myfunc() con.create_function("mytime", 1, myfunc) cur = con.cursor() cur.execute("SELECT mytime(1429100920)") print(cur.fetchone()[0]) # Результат: 15.04.2015 cur.close() con.close() input()
Результат работы приложения:
15.04.2015
На следующем шаге мы рассмотрим создание агрегатных функций.