導入 libsqlite3.0.tdb sql
建立 Header.h 並配置到 Object-C Bridging Header 數據庫
在header.h中導入sqliteswift
#import "SQLite3.h"
而後就可使用 sqlite 數據庫了數組
//ide
// ViewController.swift函數
//測試
import UIKitspa
class ViewController: UIViewController {3d
override func viewDidLoad() {指針
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var db: COpaquePointer = nil
/// 打開數據庫 是否打開成功
func openDatabase() -> Bool {
let doc = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let dbname = "test.db"
let path = doc.first! + "/" + dbname
let fm = NSFileManager.defaultManager()
let find = fm.fileExistsAtPath(path)
print("find = \(find) path = \(path)")
// 若是數據庫存在,則用sqlite3_open直接打開(不要擔憂,若是數據庫不存在sqlite3_open會自動建立)
// sqlite3_open 若是若是數據庫不存在,會新建數據庫文件
// 若是數據庫文件已經存在,就直接打開,返回句柄,不會對數據有任何影響
if sqlite3_open(path, &db) == SQLITE_OK {
print("打開數據庫成功")
// 本質上只須要運行一次就能夠了
if createTable() {
print("創表成功")
// TODO: 測試查詢數據
let sql = "SELECT id, DepartmentNo, Name FROM T_Department;"
recordSet(sql)
} else {
print("創表失敗")
}
return true
} else {
print("打開數據庫失敗")
sqlite3_close(db)
return false
}
}
/// 建立數據表,將系統須要的數據表,一次性建立
private func createTable() -> Bool {
// 準備全部數據表的 SQL
// 1> 每個 SQL 完成後都有一個 ;
// 2> 將全部創表 SQL 寫在一塊兒,每個換行添加一個 \n
let sql = "CREATE TABLE \n" +
"IF NOT EXISTS T_Department (\n" +
"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" +
"DepartmentNo CHAR(10) NOT NULL DEFAULT '',\n" +
"Name CHAR(50) NOT NULL DEFAULT '' \n" +
"); \n" +
"CREATE TABLE IF NOT EXISTS T_Employee ( \n" +
"'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \n" +
"'name' TEXT NOT NULL, \n" +
"'age' INTEGER NOT NULL, \n" +
"'department_id' INTEGER, \n" +
"CONSTRAINT 'FK_DEP_ID' FOREIGN KEY ('department_id') REFERENCES 'T_Department' ('id') \n" +
");"
var stmt:COpaquePointer = nil
//sqlite3_prepare_v2 接口把一條SQL語句解析到statement結構裏去. 使用該接口訪問數據庫是當前比較好的的一種方法
//第一個參數跟前面同樣,是個sqlite3 * 類型變量,
//第二個參數是一個 sql 語句。
//第三個參數我寫的是-1,這個參數含義是前面 sql 語句的長度。若是小於0,sqlite會自動計算它的長度(把sql語句當成以\0結尾的字符串)。
//第四個參數是sqlite3_stmt 的指針的指針。解析之後的sql語句就放在這個結構裏。
//第五個參數是錯誤信息提示,通常不用,爲nil就能夠了。
//若是這個函數執行成功(返回值是 SQLITE_OK 且 statement 不爲NULL ),那麼下面就能夠開始插入二進制數據。
let sqlReturn = sqlite3_prepare_v2(db, sql, -1, &stmt, nil);
//若是SQL語句解析出錯的話程序返回
if(sqlReturn != SQLITE_OK) {
return false;
}
//執行SQL語句
let success = sqlite3_step(stmt);
//釋放sqlite3_stmt
sqlite3_finalize(stmt);
//執行SQL語句失敗
if ( success != SQLITE_DONE) {
return false
}
return true
}
/// 執行沒有返回值的 SQL 語句
///
/// :param: sql SQL 字符串
///
/// :returns: 是否成功
func execSQL(sql: String) -> Bool {
/**
1. 數據庫指針
2. SQL 字符串的 C 語言格式
3. 回調,執行完成 SQL 指令以後的函數回調,一般都是 nil
4. 回調的第一個參數的指針
5. 錯誤信息,一般也傳入 nil
*/
return sqlite3_exec(db, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, nil, nil, nil) == SQLITE_OK
}
func insertTab() -> Bool {
if self.openDatabase(){
//這個 sql 語句特別之處在於 values 裏面有個? 號。在sqlite3_prepare函數裏,?號表示一個未定的值,它的值等下才插入。
var sql = "inser () values(?,?,?)"
sql = "update table set a=?,b=? where id =?"
sql = "delete from tab where 1=1 "
// 1. 準備語句
var stmt: COpaquePointer = nil
/**
1. 數據庫句柄
2. SQL 的 C 語言的字符串
3. SQL 的 C 語言的字符串長度 strlen,-1 會自動計算
4. stmt 的指針
5. 一般傳入 nil
*/
var suc = sqlite3_prepare_v2(db, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, &stmt, nil)
if suc == SQLITE_OK {
// let intTran = UnsafeMutablePointer<Int>(bitPattern: -1)
// let tranPointer = COpaquePointer(intTran)
// let transient = CFunctionPointer<((UnsafeMutablePointer<()>) -> Void)>(tranPointer)
//http://stackoverflow.com/questions/26883131/sqlite-transient-undefined-in-swift/26884081#26884081
let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self)
let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
//索引從1開始 這裏的數字1,2,3表明上面的第幾個問號,這裏將三個值綁定到三個綁定變量
sqlite3_bind_int(stmt, 1, 123);
sqlite3_bind_text(stmt, 2, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, SQLITE_TRANSIENT)
sqlite3_bind_text(stmt, 3, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, SQLITE_TRANSIENT)
//執行 語句
suc = sqlite3_step(stmt)
//釋放statement
sqlite3_finalize(stmt)
//關閉數據庫
sqlite3_close(db)
if suc == SQLITE_ERROR{
return false
}else{
return true
}
}else{
if let error = String.fromCString(sqlite3_errmsg(self.db)) {
let msg = "SQLiteDB - failed to prepare SQL: \(sql), Error: \(error)"
print(msg)
}
sqlite3_finalize(stmt)
sqlite3_close(db)
return false
}
}
return false
}
/// 執行 SQL 返回一個結果集(對象數組)
///
/// :param: sql SQL 字符串
func recordSet(sql: String) {
// 1. 準備語句
var stmt: COpaquePointer = nil
/**
1. 數據庫句柄
2. SQL 的 C 語言的字符串
3. SQL 的 C 語言的字符串長度 strlen,-1 會自動計算
4. stmt 的指針
5. 一般傳入 nil
*/
if sqlite3_prepare_v2(db, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, &stmt, nil) == SQLITE_OK {
// 單步獲取SQL執行的結果 -> sqlite3_setup 對應一條記錄
//查詢結果集中一條一條的遍歷全部的記錄,這裏的數字對應的是列值,注意這裏的列值,跟上面sqlite3_bind_text綁定的列值不同!必定要分開,否則會crash,只有這一處的列號不一樣,注意!
while sqlite3_step(stmt) == SQLITE_ROW {
// 獲取每一條記錄的數據
recordData(stmt)
}
}
sqlite3_finalize(stmt)
sqlite3_close(db)
}
/// 獲取每一條數據的記錄
///
/// :param: stmt prepared_statement 對象
func recordData(stmt: COpaquePointer) {
// 獲取到記錄
let count = sqlite3_column_count(stmt)
print("獲取到記錄,共有多少列 \(count) ")
// 遍歷每一列的數據
for i in 0..<count {
let type = sqlite3_column_type(stmt, i)
// 根據字段的類型,提取對應列的值
switch type {
case SQLITE_INTEGER:
print("整數 \(sqlite3_column_int64(stmt, i))")
case SQLITE_FLOAT:
print("小樹 \(sqlite3_column_double(stmt, i))")
case SQLITE_NULL:
print("空 \(NSNull())")
case SQLITE_TEXT:
let chars = UnsafePointer<CChar>(sqlite3_column_text(stmt, i))
let str = String(CString: chars, encoding: NSUTF8StringEncoding)!
print("字符串 \(str)")
case let type:
print("不支持的類型 \(type)")
}
}
}
}