qtqtsql

Easiest way to create a table with lots of columns in QT with SQL?


I'm going to create a table with these column names.

QStringList column_names = {"ID","Day","Hour","Minute","Second","Millisecond","ADC0","ADC1","ADC2","ADC3","ADC4","ADC5","ADC6","ADC7","ADC8","ADC9","ADC10","ADC11","DADC0","DADC1","DADC2","DADC3","DADC4","I0","I1","I2","I3","I4","I5","I6","I7","E0","E1","IC0","IC1","DAC0","DAC1","DAC2","PWM0","PWM1","PWM2","PWM3","PWM4","PWM5","PWM6","PWM7"};

There are different types of datatypes and some are floats. But this makes the code quite messy if I'm going to use the QSqlQuery class in QT.

Question:

Do I need to use the QSqlQuery class to create a table with columns, or can I use QSqlQueryModel class in QT instead?

My goal is to create a table with the column_names above.


Solution

  • About QSqlQueryModel:

    After reviewing some of the online Qt documentation, it appears the only way to create a table using the QSqlQueryModel requires you to subclass QSqlQueryModel: https://doc.qt.io/qt-5/qsqlquerymodel.html#details

    Otherwise, the interface of QSqlQueryModel does not perform write operations according to several locations in the documentation including: https://doc.qt.io/qt-5/qsqlquerymodel.html#setHeaderData

    Another example of the behavior described according to a few people in a thread, as well as a brief description of a solution: https://forum.qt.io/topic/35287/qsqltablemodel-read-only

    Therefore, the existing means of using QSqlQueryModel as-is involves associating a view with the object instance, querying an existing database via the QSqlQueryModel instance, and displaying results of the query in the GUI.

    About using QSqlQuery instead:

    The implementation of QSqlQuery allows posting general queries to an SQL database, including poorly structured queries, read only queries, as well as write queries. Although the initialization process of a table with a large number of columns you have listed seems annoying, it mostly depends on your use case of the database object.

    'Set and forget' use case:

    Assumptions for this use case include: infrequent or singularly large amounts of data being added every now and then, primarily reads from the database.

    Use the QSqlQuery interface to perform your writes to the database, as well as a QSqlQueryModel for the GUI(if any). The idea is you will be rarely calling the QSqlQuery interface anyway, when the query is completed, you can simply refresh the QSqlQueryModel object, as well as its corresponding view in a lock step manner. Although this solution seems less cohesive than using one or the other it will be easier to thread this kind of setup because then you could pass a QSqlQuery object around wrapped in a command class usable to the remainder of your own application.

    Additionally, the QSqlQueryModel instance would provide the view object, whatever that is, with incremental rows, no need to hand roll that using QSqlQuery.

    'Legacy dataset handling' use case:

    Assumptions for this use case include: never updating the underlying dataset.

    Use the QSqlQueryModel exclusively. If writing is really necessary subclass QSqlQueryModel. Although make sure to avoid exposing an easy means of passing in the "DROP" SQL reserve word by accident/error on the users part.

    'High throughput' use case:

    No easy solution for this one. Highly dependent on use case metrics, and other items. Perhaps sticking with QSqlQuery is recommended here if the tables are frequently accessed or sorted against common columns is best if the application is threaded very well. Each thread would get a connection as well as all the necessary query objects to execute.

    However, having a simplified, easy to refresh, read-only view object, such as QSqlQueryModel in conjunction with the QSqlQuery objects getting passed around, or generated seems like a good idea all around.

    Clearly this use case requires more testing, and information on your part to give you a better answer.

    IMPORTANT(all use cases):

    You don't have to specify every single column name in every QSqlQuery or call to QSqlQueryModel. If you will need to request a large number of column names in general, use maps/pairs to return categories of related names from the list of names provided. So for example, the "PWM#" names could be contained in a pair that returns all the strings of a similar name. Then run a for loop to append the returned values to a SQL query you are going to execute.

    I'm sure there are a few good fast substring search options out there as well to help you out. Then you could just quickly search for a header name in a string you store in a wrapper class of your design that supports the desired functionality.

    Could you provide more information about your use case that requires submitting a large number of column names at the same time?

    I can think of a better solution, possibly some code as well, if there is a better explanation of the types of queries you will be submitting, memory constraints, and or speed concerns.

    Based on your question I am assuming you are C++?