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

    Работа с базами данных в 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;

    }
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 6

      +1
      Если Вас устраивает ограничение на версию ОС не менее 3.0, то я бы порекомендовал использовать CoreData. Проблем с датой не возникает.
        0
        Я никогда не работал с SQLite, но однажды заметил, как элегантно работает MS SQL.
        Если в манагере вызвать мастера по созданию скрипта и создать скипт наполнения базы, то в полученном файле дата хранится в числе

        INSERT [dbo].[Task] ([ID], [Manager], [Date], [Client], [Category], [State], [Resume], [IsNotify], [NotifyTime], [UserID], [NotifyFlag]) VALUES (22, 1, CAST(0x9C6A0579 AS SmallDateTime), 72, N'cat2', 2, N'', 1, 15, 1, 1)

        Мне кажется что хранить целочисленные это экономнее и эффективнее чем текст.
        Можно ли сделать так же и на SQLite?
          –4
          Так как в SQLite типизация нестрогая, то особой разницы между хранением строк и чисел нету с точки зрения экономии и эффективности.
          • НЛО прилетело и опубликовало эту надпись здесь
          –1
          Да конечно можно — и возможно это даже правельнее
            0
            Так мне удобнее было для понимания

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое