QT SQL模型是否支持UPSERT?

发布于 2025-01-19 07:52:01 字数 298 浏览 2 评论 0原文

我现在在应用程序中使用QT SQL,并且可以通过使用QSQLQUERY来执行以下脚本(又称UPSERT):

INSERT INTO table_1(col_1,col_2,col_3) VALUES(val_1,val_2,val_3)
ON CONFLICT(col_1) DO UPDATE SET col_1=val_1,col_2=val_2,col_3=val_3

是否可以在模型/视图框架下实现此脚本,IE使用IE QSQLTableModel

I'm now using Qt SQL in my application, and I'm able to execute the following script (aka UPSERT) by using QSqlQuery:

INSERT INTO table_1(col_1,col_2,col_3) VALUES(val_1,val_2,val_3)
ON CONFLICT(col_1) DO UPDATE SET col_1=val_1,col_2=val_2,col_3=val_3

Is it possible to implement this under model/view framework, i.e. using QSqlTableModel?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迟月 2025-01-26 07:52:01

no,UPSERTQT中未实现,因为它在不同的数据库系统上具有不同的语法。但是您可以以这种方式实现它:

  1. Override QSQLTABLEMODEL :: INSERTROWINTOTABLE
  2. 实现UPSERT语句
  3. 复制QSQLTABLEMODELPRIVATE :: EXEC从qt源或指针黑客。

这是可以为mySQL完成的方法:

static QString prepareIdentifier(const QString &identifier,
        QSqlDriver::IdentifierType type, const QSqlDriver *driver)
{
    Q_ASSERT( driver != nullptr );
    QString ret = identifier;
    if (!driver->isIdentifierEscaped(identifier, type)) {
        ret = driver->escapeIdentifier(identifier, type);
    }
    return ret;
}

static QString upsertStatement(QSqlDriver* driver, const QString &tableName,
                        const QSqlRecord &rec, bool preparedStatement, QSqlRecord& whereValues) {

    Q_ASSERT_X(driver->dbmsType() == QSqlDriver::MySqlServer, "upsertStatement()", "not implemented");

    QString s;
    const auto tableNameString = tableName.isEmpty() ? QString()
                                    : prepareIdentifier(tableName, QSqlDriver::TableName, driver);

    s = s + QLatin1String("INSERT INTO ") + tableNameString + QLatin1String(" (");
    QString vals;
    for (int i = 0; i < rec.count(); ++i) {
        s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, driver)).append(QLatin1String(", "));
        if (preparedStatement)
            vals.append(QLatin1Char('?'));
        else
            vals.append(driver->formatValue(rec.field(i)));
        vals.append(QLatin1String(", "));
    }
    if (vals.isEmpty()) {
        s.clear();
    } else {
        vals.chop(2); // remove trailing comma
        s[s.length() - 2] = QLatin1Char(')');
        s.append(QLatin1String("VALUES (")).append(vals).append(QLatin1Char(')'));
    }
    s.append(" ON DUPLICATE KEY UPDATE ");
    QSqlRecord primaryKey = driver->primaryIndex(tableName);
    for (int i = 0; i < rec.count(); ++i) {
        if (!rec.isGenerated(i)) {
            continue;
        }
        if (primaryKey.contains(rec.fieldName(i))) {
            continue;
        }
        s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, driver)).append(QLatin1Char('='));
        if (preparedStatement) {
            s.append(QLatin1Char('?'));
            whereValues.append(rec.field(i));
        } else {
            s.append(driver->formatValue(rec.field(i)));
        }
        s.append(QLatin1String(", "));
    }
    if (s.endsWith(QLatin1String(", ")))
        s.chop(2);

    return s;
}

bool SqlTableModel::insertRowIntoTable(const QSqlRecord &values)
{
    QSqlDatabase db = database();
    QString tableName = this->tableName();

    QSqlRecord rec = values;
    emit beforeInsert(rec);

    const bool prepStatement = db.driver()->hasFeature(QSqlDriver::PreparedQueries);
    QSqlRecord whereValues;
    const QString stmt = upsertStatement(db.driver(), tableName, rec, prepStatement, whereValues);

    if (stmt.isEmpty()) {
        qDebug() << "No Fields to update";
        return false;
    }

    return exec(stmt, prepStatement, rec, whereValues);
}

bool SqlTableModel::exec(const QString &stmt, bool prepStatement,
                                 const QSqlRecord &rec, const QSqlRecord &whereValues)
{
    qDebug() << stmt;
    //qDebug() << values(rec) << values(whereValues);
    if (stmt.isEmpty())
        return false;
    QSqlDatabase db = database();
    auto editQuery = QSqlQuery(db);

    if (prepStatement) {
        if (!editQuery.prepare(stmt)) {
            return false;
        }
        int i;
        for (i = 0; i < rec.count(); ++i)
            editQuery.addBindValue(rec.value(i));
        for (i = 0; i < whereValues.count(); ++i)
            if (!whereValues.isNull(i)) {
                editQuery.addBindValue(whereValues.value(i));
            } else {
                qDebug() << "unexpected null value";
                return false;
            }
        if (!editQuery.exec()) {
            qDebug() << editQuery.lastError().text();
            return false;
        }
    } else {
        if (!editQuery.exec(stmt)) {
            qDebug() << editQuery.lastError().text();
            return false;
        }
    }
    return true;
}

完整源

No, UPSERT is not implemented in Qt because it has different syntax on different database systems. But you can implement it this way:

  1. override QSqlTableModel::insertRowIntoTable
  2. implement upsert statement
  3. copy QSqlTableModelPrivate::exec from qt sources or pointer-hack into it.

Here's how it can be done for mysql:

static QString prepareIdentifier(const QString &identifier,
        QSqlDriver::IdentifierType type, const QSqlDriver *driver)
{
    Q_ASSERT( driver != nullptr );
    QString ret = identifier;
    if (!driver->isIdentifierEscaped(identifier, type)) {
        ret = driver->escapeIdentifier(identifier, type);
    }
    return ret;
}

static QString upsertStatement(QSqlDriver* driver, const QString &tableName,
                        const QSqlRecord &rec, bool preparedStatement, QSqlRecord& whereValues) {

    Q_ASSERT_X(driver->dbmsType() == QSqlDriver::MySqlServer, "upsertStatement()", "not implemented");

    QString s;
    const auto tableNameString = tableName.isEmpty() ? QString()
                                    : prepareIdentifier(tableName, QSqlDriver::TableName, driver);

    s = s + QLatin1String("INSERT INTO ") + tableNameString + QLatin1String(" (");
    QString vals;
    for (int i = 0; i < rec.count(); ++i) {
        s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, driver)).append(QLatin1String(", "));
        if (preparedStatement)
            vals.append(QLatin1Char('?'));
        else
            vals.append(driver->formatValue(rec.field(i)));
        vals.append(QLatin1String(", "));
    }
    if (vals.isEmpty()) {
        s.clear();
    } else {
        vals.chop(2); // remove trailing comma
        s[s.length() - 2] = QLatin1Char(')');
        s.append(QLatin1String("VALUES (")).append(vals).append(QLatin1Char(')'));
    }
    s.append(" ON DUPLICATE KEY UPDATE ");
    QSqlRecord primaryKey = driver->primaryIndex(tableName);
    for (int i = 0; i < rec.count(); ++i) {
        if (!rec.isGenerated(i)) {
            continue;
        }
        if (primaryKey.contains(rec.fieldName(i))) {
            continue;
        }
        s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, driver)).append(QLatin1Char('='));
        if (preparedStatement) {
            s.append(QLatin1Char('?'));
            whereValues.append(rec.field(i));
        } else {
            s.append(driver->formatValue(rec.field(i)));
        }
        s.append(QLatin1String(", "));
    }
    if (s.endsWith(QLatin1String(", ")))
        s.chop(2);

    return s;
}

bool SqlTableModel::insertRowIntoTable(const QSqlRecord &values)
{
    QSqlDatabase db = database();
    QString tableName = this->tableName();

    QSqlRecord rec = values;
    emit beforeInsert(rec);

    const bool prepStatement = db.driver()->hasFeature(QSqlDriver::PreparedQueries);
    QSqlRecord whereValues;
    const QString stmt = upsertStatement(db.driver(), tableName, rec, prepStatement, whereValues);

    if (stmt.isEmpty()) {
        qDebug() << "No Fields to update";
        return false;
    }

    return exec(stmt, prepStatement, rec, whereValues);
}

bool SqlTableModel::exec(const QString &stmt, bool prepStatement,
                                 const QSqlRecord &rec, const QSqlRecord &whereValues)
{
    qDebug() << stmt;
    //qDebug() << values(rec) << values(whereValues);
    if (stmt.isEmpty())
        return false;
    QSqlDatabase db = database();
    auto editQuery = QSqlQuery(db);

    if (prepStatement) {
        if (!editQuery.prepare(stmt)) {
            return false;
        }
        int i;
        for (i = 0; i < rec.count(); ++i)
            editQuery.addBindValue(rec.value(i));
        for (i = 0; i < whereValues.count(); ++i)
            if (!whereValues.isNull(i)) {
                editQuery.addBindValue(whereValues.value(i));
            } else {
                qDebug() << "unexpected null value";
                return false;
            }
        if (!editQuery.exec()) {
            qDebug() << editQuery.lastError().text();
            return false;
        }
    } else {
        if (!editQuery.exec(stmt)) {
            qDebug() << editQuery.lastError().text();
            return false;
        }
    }
    return true;
}

Full source

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文