在Swift4 for iOS11中,我想附加两个SQLite数据库文件(file1.db和file2.db),以便对所有数据(即两个数据库)进行查询。
我已经使用以下代码成功地在一个SQLite数据库中实现了一个SQL查询(…这里有一个名称查询的示例…):

func readOneDB() -> String? {

    // create SQL-DB FilePath
    do {
        // create a documents-URL from filename
        self.file_1_URL = try createSQLFilePath(fileName: "file1", fileExtension: "db")
    }
    catch {
        return nil
    }
    let query =
    """
    SELECT DISTINCT n.locations
    FROM names n
    WHERE  n.name = "\(self.myName)"
    """

    // Open SQLite database
    var db: OpaquePointer? = nil
    if sqlite3_open(self.file_1_URL?.absoluteString, &db) == SQLITE_OK {

        var statement: OpaquePointer? = nil

        // Run SELECT query from db
        if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {

            // Loop through all results from query
            while sqlite3_step(statement) == SQLITE_ROW {

                let name = sqlite3_column_text(statement, 0)
                if name != nil {
                    let versionString = String(cString:name!)
                    return nameString
                } else {
                    print("name not found", terminator: "")
                    return nil
                }
            }
        } else {
            let errmsg = String(cString: sqlite3_errmsg(db))
            print("error running query: \(errmsg)")
            return nil
        }
    } else {
        print("error opening database")
        return nil
    }
    return nil
}

现在,我读到了使用下面的sql cmd可以将两个sql数据库附加在一起(以便对它们进行查询):attach
事实上,我有以下代码没有抛出异常-但仍然不能100%工作
let attachStr = "ATTACH DATABASE \'\(self.file_2_URL!)\' AS SECOND"
if (sqlite3_exec(db, attachStr, nil, &statement, nil) == SQLITE_OK) {
    print("Success!")
}

上面印着“成功!”运行代码时。
当然,使用附加代码获得成功消息时,我认为就是这样(并且db对象将两个数据库联合起来)
但事实上没有!:不幸的是,查询仍然只带来来自第一个数据库(即file1)的结果,而没有附加的第二个file2的查询结果。
怎么了?
这是完整的代码,包括附件代码和查询(见下文)。
为什么查询仍然只传递来自第一个数据库(file1)的结果,而不是来自两个数据库(即file1和file2)????
我需要在代码中进行哪些更改才能使其生效????
func readTwoDBs() -> String? {

    // create SQL-DB FilePath
    do {
        // create documents-URLs for two filenames
        self.file_1_URL = try createSQLFilePath(fileName: "file1", fileExtension: "db")
        self.file_2_URL = try createSQLFilePath(fileName: "file2", fileExtension: "db")
    }
    catch {
        return nil
    }
    let query =
    """
    SELECT DISTINCT n.locations
    FROM names n
    WHERE  n.name = "\(self.myName)"
    """

    // Open SQLite database
    var db: OpaquePointer? = nil
    if sqlite3_open(self.file_1_URL?.absoluteString, &db) == SQLITE_OK {

        var statement: OpaquePointer? = nil

        let attachStr = "ATTACH DATABASE \'\(self.file_2_URL!)\' AS SECOND"
        if (sqlite3_exec(db, attachStr, nil, &statement, nil) == SQLITE_OK) {
            print("Success!")
        }

        //// !!!!!!! Success is printed but the query still only works with file1 WHY ????????????????????

        // Run SELECT query from db
        statement = nil
        if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {

            // Loop through all results from query
            while sqlite3_step(statement) == SQLITE_ROW {

                let name = sqlite3_column_text(statement, 0)
                if name != nil {
                    let versionString = String(cString:name!)
                    return nameString
                } else {
                    print("name not found", terminator: "")
                    return nil
                }
            }
        } else {
            let errmsg = String(cString: sqlite3_errmsg(db))
            print("error running query: \(errmsg)")
            return nil
        }
    } else {
        print("error opening database")
        return nil
    }
    return nil
}

最佳答案

在乔金的帮助下,我想我找到了一个解决办法:
ATTACH cmd实际上意味着多个数据库共享同一个数据库连接。正如Joakim所指出的,如果一个人想从两个数据库文件中都得到结果,他仍然需要做两个查询!
代码如下:
(为了便于说明,该方法的返回值是一个元组,包含两个查询的两个结果(一个来自第一个数据库,另一个来自第二个数据库)

func readTwoDBs() -> (String, String)? {

    var returnValue_1: String = ""
    var returnValue_2: String = ""

    // create SQL-DB FilePath
    do {
        // create documents-URLs for two filenames
        self.file_1_URL = try createSQLFilePath(fileName: "file1", fileExtension: "db")
        self.file_2_URL = try createSQLFilePath(fileName: "file2", fileExtension: "db")
    }
    catch {
        return nil
    }
    let query_1 =
    """
    SELECT DISTINCT n.locations
    FROM names n
    WHERE  n.name = "\(self.myName)"
    """

    // !! FOR QUERY_2 YOU NEED THE "MY_DB_TWO" NAME AND ITS TABLE IN THE FROM STATEMENT !!!!!!!
    // !! THIS "MY_DB_TWO" IS GIVEN BY THE ATTACH-cmd FURTHER DOWN... !!!!!!!!
    let query_2 =
    """
    SELECT DISTINCT n.locations
    FROM MY_DB_TWO.names n
    WHERE  n.name = "\(self.myName)"
    """

    // Open SQLite database
    var db: OpaquePointer? = nil
    if sqlite3_open(self.file_1_URL?.absoluteString, &db) == SQLITE_OK {

        var statement: OpaquePointer? = nil

        let attachStr = "ATTACH DATABASE \'\(self.file_2_URL!)\' AS MY_DB_TWO"
        if (sqlite3_exec(db, attachStr, nil, &statement, nil) == SQLITE_OK) {
            print("Success!")
        }

        // Run SELECT query Nr1 from main.db
        statement = nil
        if sqlite3_prepare_v2(db, query_1, -1, &statement, nil) == SQLITE_OK {

            // Loop through all results from query
            while sqlite3_step(statement) == SQLITE_ROW {

                let name = sqlite3_column_text(statement, 0)
                if name != nil {
                    let nameString = String(cString:name!)
                    returnValue_1 = nameString
                } else {
                    print("name not found", terminator: "")
                    returnValue_1 = ""
                }
            }
        } else {
            let errmsg = String(cString: sqlite3_errmsg(db))
            print("error running query: \(errmsg)")
            returnValue_1 = ""
        }

        // Run SELECT query Nr2 from MY_DB_TWO
        statement = nil
        if sqlite3_prepare_v2(db, query_2, -1, &statement, nil) == SQLITE_OK {

            // Loop through all results from query
            while sqlite3_step(statement) == SQLITE_ROW {

                let name = sqlite3_column_text(statement, 0)
                if name != nil {
                    let nameString = String(cString:name!)
                    returnValue_2 = nameString
                } else {
                    print("name not found", terminator: "")
                    returnValue_2 = ""
                }
            }
        } else {
            let errmsg = String(cString: sqlite3_errmsg(db))
            print("error running query: \(errmsg)")
            returnValue_2 = ""
        }
    } else {
        print("error opening database")
    }

    return (returnValue_1, returnValue_2)
}

10-04 10:47
查看更多