IT Notes

SQL под Qt: Начало

Введение

Эта заметка вкратце познакомит вас с основами использования модулей Qt для работы с реляционными базами данных. Предполагается, что знание SQL у вас уже имеется, хотя и не является столь критичным для понимания представленных примеров.

Рассматриваются базовые операции, необходимые для начала работы:

  • Открытие базы данных;
  • Выполнение запросов;
  • Выборка записей.

Подключение модуля sql к Qt-проекту

Для того, чтобы встроенные в Qt возможности для работы с SQL заработали, необходимо добавить в pro-файл следующую инструкцию:

QT += sql

Однако учитывайте, что драйвера различных баз данных устанавливаются в виде плагинов и могут отсутствовать в вашем дистрибутиве Qt. Особенно актуальной это проблема является под Windows в связи с лицензионными ограничениями на распространение бинарных пакетов. О том, как собрать нужный плагин, мы поговорим в другой раз.

Подключение к базе данных QSQLITE

Для простоты воспользуемся драйвером QSQLITE (предназначен для работы с SQLite), поскольку он предустановлен во всех известных мне дистрибутивах Qt. К тому же, вам не потребуется устанавливать отдельную систему управлениями базами данных.

Рассмотрим соответствующий код подключения:

#include <QDebug>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>

#include <QDate>

int main() {
    QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
    db.setDatabaseName( "test" );
    if( !db.open() ) {
        qDebug() << db.lastError().text();
        return 1;
    }

    return 0;
}

Если все прошло нормально, то в результате работы этого кода у вас появится пустой файл test в рабочем каталоге приложения. Так же обратите внимание на следующие функции-члены класса QSqlDatabase, которые потребуются вам, когда вы решите воспользоваться внешним сервером баз данных:

  • isValid();
  • setHostName();
  • setPort();
  • setDatabaseName();
  • setUserName();
  • setPassword();

Выполнение запросов с помощью QSqlQuery

Создадим в открытой базе данных новую таблицу с помощью QSqlQuery:

#include <QDebug>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>

#include <QDate>

int main() {
    // Предыдущий код убран для краткости

    QSqlQuery query( db );
    if( !query.exec(
                "CREATE TABLE User("
                "   login VARCHAR( 200 ) NOT NULL,"
                "   registration_date DATE NOT NULL"
                ")"
    ) ) {
        qDebug() << db.lastError().text();
        return 1;
    }

    return 0;
}

Аналогичным образом с помощью функции-члена exec() можно выполнять любые запросы к базе данных. Однако имеется одна тонкость.

Вставка записей в базу данных

Если запрос использует внешние данные, то в целях безопасности не вставляйте их напрямую, а используйте комбинацию prepare() и bindValue():

#include <QDebug>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>

#include <QDate>

int main() {
    // Предыдущий код убран для краткости

    query.prepare(
        "INSERT INTO User( login, registration_date ) "
        "   VALUES( :login, :registration_date )"
    );
    query.bindValue( ":login", "Hello" );
    query.bindValue( ":registration_date", QDate::currentDate() );
    if( !query.exec() ) {
        qDebug() << db.lastError().text();
        return 1;
    }

    return 0;
}

Выборка записей из базы данных

Теперь рассмотрим способ получения записей из базы данных:

#include <QDebug>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>

#include <QDate>

int main() {
    // Предыдущий код убран для краткости

    if( !query.exec( "SELECT * FROM User" ) ) {
        qDebug() << db.lastError().text();
        return 1;
    }
    QSqlRecord rec = query.record();
    const int loginIndex = rec.indexOf( "login" );
    const int registrationDateIndex = rec.indexOf( "registration_date" );
    while( query.next() ) {
        qDebug() << query.value( loginIndex ) << query.value( registrationDateIndex );
    }

    return 0;
}

Заключение

Подводя итоги приведу полный листинг рассмотренного примера (обратите внимание на его завершение, дополненное кодом удаления таблицы и закрытия соединения с базой данных):

#include <QDebug>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>

#include <QDate>

int main() {
    QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
    db.setDatabaseName( "test" );
    if( !db.open() ) {
        qDebug() << db.lastError().text();
        return 1;
    }

    QSqlQuery query( db );
    if( !query.exec(
                "CREATE TABLE User("
                "   login VARCHAR( 200 ) NOT NULL,"
                "   registration_date DATE NOT NULL"
                ")"
    ) ) {
        qDebug() << db.lastError().text();
        return 1;
    }

    query.prepare(
        "INSERT INTO User( login, registration_date ) "
        "   VALUES( :login, :registration_date )"
    );
    query.bindValue( ":login", "Hello" );
    query.bindValue( ":registration_date", QDate::currentDate() );
    if( !query.exec() ) {
        qDebug() << db.lastError().text();
        return 1;
    }

    if( !query.exec( "SELECT * FROM User" ) ) {
        qDebug() << db.lastError().text();
        return 1;
    }
    QSqlRecord rec = query.record();
    const int loginIndex = rec.indexOf( "login" );
    const int registrationDateIndex = rec.indexOf( "registration_date" );
    while( query.next() ) {
        qDebug() << query.value( loginIndex ) << query.value( registrationDateIndex );
    }

    // Удаляем таблицу перед выходом
    query.exec( "DROP TABLE User" );

    // Не обязательно, но в крупной системе лучше закрывать соединение с БД, когда оно больше не требуется
    db.close();

    return 0;
}

Похожие публикации