问题
In Swift4 for iOS11 I would like to attach two SQLite database-files (file1.db and file2.db) in order to make a query over all data (i.e. over both databases).
I have successfully implemented a SQL-query in one SQLite database using the following code (..here with an example of a name-query...):
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
}
Now, I read that with the following sql-cmd it is possible to attach two SQL-databases together (in order to make a query over both of them): ATTACH
In fact, I have the following code that does not throw an exception - but still not working 100%
let attachStr = "ATTACH DATABASE \'\(self.file_2_URL!)\' AS SECOND"
if (sqlite3_exec(db, attachStr, nil, &statement, nil) == SQLITE_OK) {
print("Success!")
}
There is a print of "Success!" when running the code.
Of course, getting the success-message with the attach-code, I thought this is it (and the db-object has both databases united)
But actually NO ! : The query still only brings results from the first database (i.e. file1) and no query-results of the attached second file2, unfortunately.
What is wrong ?
Here is the complete code with the attachment-code and the query (see below).
Why is the query still only delivering results from the first database (file1) and not from both databases (i.e. file1 and file2) ????
What changes do I need to make in the code for this to work ????
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
}
回答1:
With the help of Joakim, I think I found a solution:
The ATTACH-cmd actually means that more than one database is sharing the same database-connection. As Joakim pointed out, one still needs to do two queries if one wants to get results from both database-files!
Here is the code : (for illustration purposes, the method's return-value is a tuple containing the two results of the two queries (one from the first database, second one from the second database)
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)
}
来源:https://stackoverflow.com/questions/49440681/attach-two-sqlite-db-files-to-query-over-both-files-in-swift