Запрос динамического выбора QtSql с несколькими фильтрами WHERE

  • Мне нужно выполнить любой запрос на выборку, используя тот же метод.
  • Таким образом, запрос должен фильтровать выбранные данные, используя одно или несколько значений.
  • Фильтры хранятся на карте, в которой имя столбца используется в качестве ключа, а значение фильтрации — в качестве значения.
  • Итак, мой вопрос: как динамически добавлять фильтры в оператор Select?
  • Что я пробовал:

    <сильный>1. Класс QSqlQueryModel: я мог бы создать объект QSqlQueryModel и задать запрос для извлечения всех данных таблицы, но я не смог найти в этом классе никаких функций для фильтрации этих данных:

       QSqlQueryModel *model = new QSqlQueryModel;
       model->setQuery("SELECT * FROM employee");
    

    <сильный>2. QSqlTableModel: этот класс используется для просмотра данных таблицы в qtableView, я могу использовать этот класс для чтения данных таблицы, а затем фильтровать эти данные следующим образом (я еще не пробовал):

     QSqlTableModel *model = new QSqlTableModel
     model->setTable("employee");
     model->setEditStrategy(QSqlTableModel::OnManualSubmit);
     model->select();
     model->setFilter("colum5 > 10");
     // I can use after that data() method to retrieve filtered data. 
    

    <сильный>3. For Loop Я думал об использовании цикла for для прямого добавления фильтров, но я бы предпочел лучший способ, потому что я считаю, что QT предлагает такую ​​услугу.


Метод должен выглядеть следующим образом:

/**
 * @brief getData executes sql select query.
 * @param query [out] QSqlQuery query object after executing the query.
 * @param queryFilters [in] map of query filters (column-name, filter- 
   value).
 * @param table [in] table name.
 * @return 
 */
bool getData(QSqlQuery &query, std::map<std::string,QVariant> &queryFilters, 
std::string &table){
        bool status = false;
        std::string queryText = "SELECT * from " + table + " WHERE  ";
        // I should apply filters from queryFilters map here.
        return status;
} 

person Samir N Ahmad    schedule 18.11.2018    source источник
comment
Почему бы не использовать [QMap](doc.qt.io/qt-5/qmap.html)?   -  person TrebledJ    schedule 18.11.2018
comment
Речь идет не об использовании карты или другого класса stl. Я спрашиваю о том, как динамически добавлять фильтры в оператор запроса.   -  person Samir N Ahmad    schedule 18.11.2018
comment
Вы столкнетесь с большим количеством преобразований между типами STL/QTL. Так что можно было бы начать использовать QString и QMap/QHash. Вы пытались использовать цикл в этом отношении? :-)   -  person TrebledJ    schedule 18.11.2018
comment
Ага, я пропустил этот момент. Спасибо!   -  person Samir N Ahmad    schedule 18.11.2018
comment
Обычно с variable числом переменных лучше всего использовать циклы. Кроме того, просто глядя на вашу строку, "SELECT * from" + table + "WHERE " будьте осторожны с пробелами до/после table, если только вы не можете гарантировать наличие пробелов. SELECT * frommyTableWHERE... не будет выполняться.   -  person TrebledJ    schedule 18.11.2018
comment
Я думал об использовании цикла для этого вопроса. Но я подумал, что есть лучший способ использовать некоторые классы qt, такие как: QSqlQueryModel   -  person Samir N Ahmad    schedule 18.11.2018
comment
Спасибо за ваш совет, я думаю, что я буду использовать цикл for непосредственно внутри оператора запроса в качестве моего последнего решения! :).   -  person Samir N Ahmad    schedule 18.11.2018
comment
Привет еще раз. Если вы считаете, что QSqlQueryModel может быть лучшим решением, включите его в свой вопрос, поскольку он расскажет нам о вашем мыслительном процессе: что сработало, что не сработало.   -  person TrebledJ    schedule 18.11.2018


Ответы (1)


Есть несколько способов сделать это.

Использование цикла for с std::map.

Используйте цикл for для перебора значений пары ключей.

bool getData(QSqlQuery &query, const std::map<std::string,QVariant> &queryFilters,
             std::string &table)
{
    // ...

    std::string queryText = "SELECT * from " + table + " WHERE";
    
    for (auto it = queryFilters.begin(); it != queryFilters.end(); )
    {
        queryText += " " + it->first + "='" + it->second.toString().toStdString() + "'";
    
        it++;
        // check the iterator isn't the last iterator
        if (it != queryFilters.end())
            queryText += " AND";    // separate your "filters" using an AND
    }

    // ...      
}

Использование цикла for с QMap.

Но, черт возьми, это Qt, так почему бы не воспользоваться преимуществами QMap, QStringList и QString типы QTL.

bool getData(QSqlQuery &query, const QMap<QString, QVariant> &queryFilters,
             const QString &table)
{
    //  ...
    
    QString queryText = "SELECT * from " + table + " WHERE ";
    QStringList filters;
    foreach (const QString &filterKey, queryFilters.keys())
        filters << filterKey + "='" + queryFilters.value(filterKey).toString() + "'";
    
    queryText += filters.join(" AND ");
    
    //  ...
    
}

Обратите внимание, что foreach — это макрос, определенный в Qt. См. ключевое слово foreach.

Чтобы узнать о других типах QTL, см. раздел контейнеры.


QSqlQueryModel???

Я не могу сказать из вашего вопроса и комментариев, действительно ли у вас есть модель/представление/виджет таблицы sql в фоновом режиме или вы используете что-то совершенно другое.

Я думал об использовании цикла для этого вопроса. Но я подумал, что есть лучший способ использовать некоторые классы qt, такие как: QSqlQueryModel

Конечно, просто просматривая документацию, QSqlQueryModel не имеет фильтра характерная черта.

Но... QSqlTableModel имеет эту функцию. Положительным моментом является то, что если у вас где-то уже есть QSqlQueryModel, вы можете обновить его до QSqlTableModel, так как последний наследует первый. Но опять же, у меня недостаточно информации, чтобы судить, поэтому я просто веду вас в темноте.

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

person TrebledJ    schedule 18.11.2018
comment
Спасибо, я думал об использовании QsqlTableModel. Но я думаю, что он должен получить все данные таблицы, прежде чем я смогу выполнить какой-либо процесс. И я обновлю свой вопрос и добавлю больше деталей. - person Samir N Ahmad; 18.11.2018
comment
Я думаю, что использование цикла foreach на данный момент является лучшим решением. Я отметил этот ответ как принятый. Однако я буду обновлять свой вопрос всякий раз, когда найду другой подход. - person Samir N Ahmad; 18.11.2018
comment
Рад, что вы нашли это несколько полезным. for петли должны быть самыми простыми. :-) Похоже, вы обеспокоены тем, что циклы for не справятся с этим. ???? Много фильтров? - person TrebledJ; 18.11.2018
comment
Я думаю, что фильтров не так уж много! Сейчас я буду использовать цикл foreach. И я также буду использовать классы QTL вместо STL :). - person Samir N Ahmad; 18.11.2018