首页 > 解决方案 > 如何使用 swift 在 SQLite 数据库中插入一行?

问题描述

我有一个 SQLITE3 数据库,其中有两个表,主表和活动表。我试图在主表中插入一行只是为了检查它是否有效,使用我能够插入的终端上的 sql 命令,但不能通过 swift 插入。数据库已连接,允许我使用 swift 从数据库中读取,但不能写入。

let insertStatementString = "INSERT INTO main (DATE) VALUES (?);"

func insert() {
    var insertStatement: OpaquePointer?
    //1
    if sqlite3_prepare_v2(mySQLDB,insertStatementString, -1, &insertStatement, nil) == SQLITE_OK {
        let date: NSString = "14071999"
        sqlite3_bind_text(insertStatement,1,date.utf8String, -1, nil)

        if sqlite3_step(insertStatement) == SQLITE_DONE {
            print("\nSuccessfully inserted row")
        } else
        { print("\nCould not insert a row")
        }
    }
    else
    { print("\nInsert statement not prepared")
    }
    sqlite3_finalize(insertStatement)
}

当程序到达“if sqlite3_step(insertStatement) == SQLITE_DONE”时,它会跳到“无法插入行”。谁能明白为什么会出错?

标签: sqlswiftsqlite

解决方案


如果您的插入失败,您应该打印错误消息 ,sqlite3_errmsg它将准确地告诉您出了什么问题。

FWIW,您的代码对我有用,所以它可能不包含在您的问题中,例如您如何打开数据库和/或如何定义表。可能的问题包括:

  • 插入只读数据库(例如,在包中打开的只读数据库,sqlite3_open_v2以只读模式显式打开等);
  • 你的绑定语句失败(你真的应该在那里检查是否成功);
  • 在该列上有一个唯一键并且在某处已经有这个值;或者
  • 具有未提供的其他必需 ( NOT NULL) 列。

无论如何,记录错误消息将消除任何歧义。

例如

func insert() {
    var insertStatement: OpaquePointer?

    guard sqlite3_prepare_v2(mySQLDB, insertStatementString, -1, &insertStatement, nil) == SQLITE_OK else {
        printError(with: "INSERT statement not prepared")
        return
    }

    defer { sqlite3_finalize(insertStatement) }

    let date = "14071999"
    guard sqlite3_bind_text(insertStatement, 1, date.cString(using: .utf8), -1, SQLITE_TRANSIENT) == SQLITE_OK else {
        printError(with: "Bind for INSERT failed")
        return
    }

    guard sqlite3_step(insertStatement) == SQLITE_DONE else {
        printError(with: "Could not insert a row")
        return
    }

    print("Successfully inserted row")
}

func printError(with message: String) {
    let errmsg = sqlite3_errmsg(mySQLDB).flatMap { String(cString: $0) } ?? "Unknown error"
    print(message, errmsg)
}

在哪里

internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)

虽然我用guard语句构建了这个,即使你坚持你的if模式,也要确保你只有sqlite3_finalize在准备语句成功时才这样做。如果准备失败,则最终确定是没有意义的。

SQLITE_TRANSIENT使用绑定参数也是谨慎的。


推荐阅读