20 September 2009

Работа с базами данных в iPhone, SQLite и работа с датами

Lumber room
Работа с базами данных в iPhone, SQLite и работа с датами

Известно что SQLite в борьбе за облегченность и компактность напрямую не поддерживает формат «Даты». Встретившись с данной проблемой при создании iPhone приложения (а SQLite это единственное СУБД для iPhone), я не нашёл ни одной достойной документации на русском языке. Что и вызвало желание написать данный пост.

Для решения данного вопроса я обратился на сайт www.sqlite.org/lang_datefunc.html

В моем случае дату я решил хранить в текстовом формате (т.е. тип данных TEXT):

CREATE TABLE regDoc('id' INTEGER PRIMARY KEY AUTOINCREMENT, 'nameDoc' TEXT, 'dateDoc' TEXT)

При работе с таким подходом главное соблюдать формат представления данных (даты) на протяжение всего приложения.

SQLite поддерживает следующие функции работы с датой:

Function (Равна -)Equivalent strftime()
date(...) — strftime('%Y-%m-%d', ...)
time(...) — strftime('%H:%M:%S', ...)
datetime(...) — strftime('%Y-%m-%d %H:%M:%S', ...)
julianday(...) — strftime('%J', ...)

Использование основных функций имеет сложности с форматами даты для стран не Европы и США так как например в России дата имеет формат %d.%m.%Y, поэтому я использую аналог этих функций strftime().

Пример работы с датой в SQLite

const char *sql = «select id,nameDoc,dateDoc from regDoc where (strftime('%d.%m.%Y',dateDoc)<=strftime('%d.%m.%Y',?))and (strftime('%d.%m.%Y',dateDoc)>=strftime('%d.%m.%Y',?)) order by strftime('%d.%m.%Y',dateDoc) DESC»;


Здесь мы видим условия отбора по дате и сортировка. Дата в таблице хранится как текст.
Разберем условие

(strftime('%d.%m.%Y',dateDoc)<=strftime('%d.%m.%Y',?))

Что означает — Если dateDoc меньше либо равно введенной даты

Пример полной функции работы SQLite и Objective-C (Xcode)
-(NSMutableArray *)selectListDocFrom:(NSString *)dateOn:(NSString *)dateFrom:(int)flagInOut{
// Подключаемся к базе данных (процедуру подключения в этом блоке не станем // описывать)
if ([self initConnect]) {
sqlite3_stmt *statement;
// Формируем запрос — знак ? Это будущий параметр выборки (его значение
// задается далее
const char *sql = "select id,nameDoc,dateDoc from regDoc where (strftime('%d.%m.%Y',dateDoc)<=strftime('%d.%m.%Y',?)) and(strftime('%d.%m.%Y',dateDoc)>=strftime('%d.%m.%Y',?)) order by strftime('%d.%m.%Y',dateDoc) DESC";

// Компилируем запрос в байткод перед отправкой в базу данных
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
// Производим постановку параметров в компилированный запрос
// Второй параметр в методе sqlite3_bind_text указывает в место какого по
//счету знака вопроса подставить ЗНАЧЕНИЕ !Внимание этот параметр
//начинается с 1 а не с 0
sqlite3_bind_text(statement, 1, [dateOn UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [dateFrom UTF8String], -1, SQLITE_TRANSIENT);
//Условия нужные для приложения — НЕЗАБЫВАЕМ что данные для запроса
//предоставляются в кодировке UTF8String
if (flagInOut==0)
{
sqlite3_bind_text(statement, 3, [@"+" UTF8String], -1, SQLITE_TRANSIENT);
} else if (flagInOut==1)
{
sqlite3_bind_text(statement, 3, [@"-" UTF8String], -1, SQLITE_TRANSIENT);
}
//Далее выполняем запрос
while (sqlite3_step(statement) == SQLITE_ROW) {
//Перебор результата запроса
//В переборе мы видим что доступ к результату осуществляется методом
//sqlite3_column_text или sqlite3_column_int или sqlite3_column_float
//где первый параметр есть результат запроса а второй номер поля из запроса по
//даннай строке (картеж (кто помнит институт)) НАЧИНАЕТСЯ с 0 а не с 1

[self.records addObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%d",sqlite3_column_int(statement, 0)],@"id", [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 1)], @"dateDoc",[NSString stringWithFormat:@"%00.00f",sqlite3_column_double(statement, 2)],@"summa",[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 3)],@"typeOperation",nil]];
}
//Если нет ошибок мы возвращаем результат и прекращаем выполнения
//цикла выборки данных
return self.records;

} else
//В случай выборки данных Сообщаем о ней и закрываем базу
{NSAssert1(NO, @"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));};
} else {
//В случай формирования запроса Сообщаем о ней и закрываем базу

NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
}
return nil;

}
Tags:iphonesqliteobjective-cmac os
Hubs: Lumber room
+1
835 10
Comments 6
Top of the last 24 hours