4、在DBMS中使用SQL語言
4.1 SQL與本地C++應用程式接口
通過使用一個“本地”C++API和API 調用的SQL語句,Symbian系統的DBMS支援很多操作。在很早的版本中,對SQL的支援僅限于選擇語句;私有本地C++API提供了許多方法,用于操作資料庫。目前,對SQL的支援豐富了很多。從開發者的觀點來看,字面上的意思可以被了解為大多數操作可以通過兩種方法完成。
總的來說,使用SQL的代碼是簡單的,其執行速度也很快,這就是SQL受歡迎的原因。但是,對于SQL的使用,存在一些限制。例如,長事務,壓縮操作,恢複操作以及二進制列的更新操作需要使用C++ API。此外,對大量資料的SQL插入操作比使用等價的C++ API 要慢。
需要指出的是,從一開始,DBMS引擎就不支援完全的SQL操作;其僅面向有限資源設計,是以其不具有執行基于伺服器SQL的能力。雖然受到這種限制,SQL的執行效果在面向日益變化的移動裝置需求上已足夠強大。
!提示:本地與SQL DBMS語句兩者在特定環境下都可能有一些優點或缺點,并且一些操作僅可通過其中一種方式來完成。開發人員需要留意這個現象,并且為其應用程式預計的耗費而定制解決方案。關于特性的更多特征可以在Symbian 網站上的SDK文檔中擷取。
在Symbian系統的DBMS中,SQL語句清晰的傳遞給SQL引擎,舉個例子,C++代碼傳遞一個帶有串的描述符,進而擷取解釋用的整個SQL語句。
4.2 選擇語句的細目
做為經常使用的SQL語句,本節将詳細介紹選擇語句的一些細節。在此,僅從透明性的角度看,不帶有Symbian系統DBMS成員函數代碼所嵌入的SQL文法占據的篇幅較大。4.3節,“支援SQL子集”,給出了相關語句文法項目的完全細目。
選擇語句将傳回一個可以擷取真實行資料的行集。這類選擇語句有以下基本格式:
SELECT select-list FROM table-name [ WHERE search-condition ] [ ORDER BY sort-order ]
select-list 有兩種格式。指定符*以未定義順序傳回表中的所有行給行集。指定一個逗号分離清單将定義将傳回哪行以及它們的具體順序給行集。
table-name關聯于資料庫中已存在的表。
search-condition定義一些條件,使一行與行集合中資料相比對。其包含Boolean型的下列操作:
Boolean-term[或 search-condition] 例如,
a=1 OR NOT b=2 AND c=3
一個查詢條件可以由一個單一謂詞定義;更複雜的搜尋由使用AND,OR和NOT的複合謂詞組成,圓括号用于限定這些操作的次序。如果不是用括号,謂詞優先級是NOT,AND,最後是OR。
是以,
a=1 OR NOT b=2 AND c=3
等價于:
(a=1 OR ((NOT b=2) AND c=3))
!提示:在SQL中,等号并不是指派運算符。
一個search-condition 同樣使用RDbRowSet::FindL() 和 RDbRowConstraint::Open(),通過使用RDbRowSet::FindL()可以确定行集的哪一行将被傳回,使用RDbRowSet::MatchL()來确定比對行。
謂詞用于組建搜尋條件的塊。有三種類型:comparison,like,和null;每種都會對標明表中的列條件進行測試。
一個comparison謂詞與帶有文字值得列值相比較。列comparison是類型獨立的,是以其對應的語句必須有相同的類型,數字列進行數字性比較,文本列進行詞彙比較,日期列進行曆史性比較。。二進制列無法進行比較。
Like謂詞被用于決定一個文本列是否與模式串相比對。可參看函數TDesc::Match()的說明。
Null謂詞用于測試一列是否是空的。其适用于所有列類型。
在選擇語句中,Sort-order由ORDER BY來定義。如果該子句沒有使用,所展示的行順序也是也是未定義的。使用Sort-order的列可以增序(預設)或降序來擷取資料,使用降序時,行序号雖行數增加而遞減。
一個嵌入式選擇語句的例子是:
_LIT(KSQLStatement,"SELECT Author, Title FROM Books WHERE Author = ’Brown, Dale’ ORDER BY Author, Title");
...
User::LeaveIfError(view.Prepare(iBookDb, TDbQuery(KSQLStatement,
EDbCompareNormal)));
...
這裡是_LIT宏,其裝載了完整的SQL語句,并将其裝入KSQLStatement描述符中,作為TDbQuery()的一個參數而使用。
!提示:RDbView類使用Select語句來獲知哪些資料在行集中以及如果将這些資料顯示出來。查詢語句被傳遞給RDbView::Preare(),做為其的參數,并被包裹在TDbQuery對象中。
4.3 支援SQL子集
下列清單
顯示了SQL子集在Symbian系統得DBMS中執行的情況。
項 目 說 明
add-column-set add-column-spec | ( add-column-spec,… )
add-column-spec 列定義資料類型
boolean-factor [ NOT boolean-primary ]
boolean-primary 謂詞 | ( 查找條件 )
boolean-term boolean-factor [ AND boolean-term ]
column-definition 列定義資料類型[ NOT NULL ]
column-identifier 使用者定義名
column-value literal | NULL
comparison-operator < | > | <= | >= | = | <>
comparison-predicate 列定義 比較操作 逐字操作
data-type BIT | [ UNSIGNED ] TINYINT | [ UNSIGNED ] SMALLINT | [ UNSIGNED ] INTEGER | COUNTER | BIGINT | REAL | FLOAT | DOUBLE [ PRECISION ] | DATE | TIME | TIMESTAMP | CHAR [ (n) ] | VARCHAR [ (n) ] | LONG VARCHAR | BINARY [ (n) ] | VARBINARY [ (n) ] | LONG VARBINARY
date-literal #{資料表達式}#
提示:日期時間表達式可由 TTime::Parse()轉化.
digit 0 | 1 | 2 | ... 8 | 9
drop-column-set 列定義 | ( column-identifier,… )
index-name 使用者定義名
letter a | b ... y | z | A | B ... Y | Z
like-predicate 列定義 [ NOT ] LIKE 類型值
literal 串值 | 數字型 | 日期型
項 目
說 明
null-predicate
列标示符 IS [ NOT ] NULL
numeric-literal
{數字類型}
提示: 數字類型可由 Tlex::Val(TInt64&) 與Tlex::Val(TReal&)解析
pattern-value
串
提示: 當使用通配符時,DBMS使用檔案協定而非SQL标準字元作為模式掩碼:
? 代表任意一個字元 ,*代表任意長度的字元。 相應地,标準SQL使用下劃線(_)和百分号(%)。
predicate
比較謂詞 | 相似謂詞 | 空謂詞
search-condition
Bool 量 [ OR 查詢條件 ]
select-list
* | 列定義符,…
sort-specification
列定義符 [ ASC | DESC ]
string-literal
'{字母}’
提示: Character strings can contain any text character. Single quote characters can be embedded by using two consecutive single quote characters (‘’). “”字元串可以容納任意文本屬性,但一的查詢字可以通過兩個””來獲得
table-name
使用者定義名
update-column
列定義值r = column-value
user-defined-name
字母[ 字母 | 數字 | _ ]...
4.4 使用TDbQuery 類
該類的設計目的是傳遞一些能夠容納SQL的描述符,用以替代預設組織方式為普通文本比較的TDbQuery對象。例如,在下列代碼片斷中:
_LIT(KSQLStatement ="SELECT Author, Title FROM Books WHERE Author LIKE 'BR*'");
RDbView dbview;
view.Prepare(iBookDb, KSQLStatement);
the view.Prepare statement is functionally equivalent to:
view.Prepare(iBookDb, TDbQuery(KSQLStatement, EDbCompareNormal));
為了确定其他比較類型,查詢對象必須安規定格式定義,例如:
view.Prepare(iBookDb, TDbQuery(KSQLStatement, EDbCompareFolded));
4.5 SQL架構與資料更新
可以通過使用SQL指令對SQL架構和資料進行修改,DBMS接口中等價的函數為RDbDatabase和RDbIncremental。
提示:使用SQL語句可能不能完成本地DBMS API所提供的全部功能。
4.5.1 資料庫定義語言(DDL)
DDL被用來修改資料庫中的進階功能;這些功能包括在資料庫中建立和删除表以及索引。
DDL語句不能在資料庫中修改資料;然而,當一個表被删除時,表名下的所有資料都丢失了。删除一個索引即簡單的移除了通過該索引擷取特殊的表資料的能力。
4.5.1.1 建立表語句
CREATE TABLE table-name (column-definition,…)
4.5.1.2 删除表語句
DROP TABLE table-name
4.5.1.3 修改表語句
ALTER TABLE table-name { ADD add-column-set [ DROP drop-column-set ] | DROP drop-column-set }
4.5.1.4 建立索引語句
CREATE [ UNIQUE ] INDEX index-name ON table-name ( sort-specification,… )
4.5.1.5 删除索引語句
DROP INDEX index-name FROM table-name
4.5.2 SQL 資料跟新語言(DML)
DML語言可在列級修改資料庫,用法包括行插入操作,删除操作以及更新操作。
DML語句可以修改資料庫中已經存在的資料内容。
4.5.2.1 插入語句
INSERT INTO table-name [ ( column-identifier,… ) ] VALUES ( column-value,… )
4.5.2.2 删除語句
DELETE FROM table-name [ WHERE search-condition ]
4.5.2.3 更新語句
UPDATE table-name SET update-column,… [ WHERE search-condition ]
4.5.3 例子
使用DDL或DML語句最簡單的方法是執行RdbDatabase。如果操作耗時太長,推薦使用增量方法(參見第5章,“增量資料庫操作”)。
下列代碼片斷簡要顯示了資料庫架構與資料的更新:
private: // 資料成員
RDbStoreDatabase iBookDb; // 可以用 RDbNamedDatabase 替換
...
TInt CBookDb::AddDateColumn()
{
_LIT(KSqlAddDate, "ALTER TABLE Books ADD PublishDate DATE");
return iBookDb.Execute(KSqlAddDate);
}
TInt CBookDb::DropBooksTable()
{
_LIT(KSqlDropBooks, "DROP TABLE Books");
return iBookDb.Execute(KSqlDropBooks);
}
TInt CbookDb::DeleteAllBooks()
{
_LIT(KSqlDeleteAllBooks, "DELETE FROM Books");
return iBookDb.Execute(KSqlDeleteAllBooks);
}
// 删除以F-letter名字起始的書。
TInt CbookDb::DeleteFBooks()
{
_LIT(KSqlDeleteFBooks, "DELETE FROM Books where
Title like ‘F*’");
return iBookDb.Execute(KSqlDeleteFBooks);
}
TInt CBookDb::UpdateBookTitle(const TDesC& aOldTitleKey,
const TDesC& aNewTitle)
{
_LIT(KSQLUpdateStart, "UPDATE Books SET Title = '");
_LIT(KSQLUpdateMiddle, "' WHERE Title = '");
_LIT(KSQLUpdateEnd, "'");
// SQL: UPDATE Books SET Title = ‘aNewTitle’
// WHERE Title = ‘aOldTitleKey’
TBuf<KCustomSqlMaxLength> sqlStr;
sqlStr.Append(KSQLUpdateStart);
sqlStr.Append(aNewTitle);
sqlStr.Append(KSQLUpdateMiddle);
sqlStr.Append(aOldTitleKey);
sqlStr.Append(KSQLUpdateEnd);
return iBookDb.Execute(sqlStr);
}