索引的目的有三: 快速定位、排序、建立主從表. 下面是相關屬性與方法:
IndexDefs; { }
IndexFIEldCount; { }
IndexFIEldNames; { }
IndexFIElds[]; { }
IndexName; { }
AddIndex(); { }
DeleteIndex(); { }
GetIndexInfo(); { }
GetIndexNames(); { }
添加索引的方法有二:
1、用 IndexFIEldNames 通過字段名(多個字段用 ; 隔開)指定臨時索引;
2、通過 IndexDefs.AddIndexDef 或 AddIndex 建立索引, 然後用 IndexName 指定為當前索引.
兩種方法都可以在設計時完成; 後者會有更多功能, 譬如倒排序; 兩種方法是互斥的, 指定一個會自動取消另一個.
TClIEntDataSet 會自動生成兩個默認索引: DEFAULT_ORDER、CHANGEINDEX; 它們都不允許用戶刪改.
CHANGEINDEX 是用於 Delta(日志)的.
DEFAULT_ORDER 可用於恢復默認排序; 它可能已經和某些字段關聯, 如(XML 源碼):
<PARAMS DEFAULT_ORDER="1" PRIMARY_KEY="1" ... /> 或
<PARAMS DEFAULT_ORDER="1 2" PRIMARY_KEY="1 2" ... />
關於臨時索引最常用的代碼是在 DBGrid 的 OnTitleClick 事件中更換索引, 如:
{ 根據當前字段排序 }
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
if not Column.FIEld.IsBlob then { 不能給大二進制字段建立索引或排序 }
ClientDataSet1.IndexFieldNames := Column.FIEldName;
end;
{ 恢復默認排序 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ClIEntDataSet1.IndexName := 'DEFAULT_ORDER';
end;
使用 IndexFieldNames 可指定多個字段, 如: ClientDataSet1.IndexFIEldNames := '字段x; 字段y; 字段z';
此時順序很重要, 這裡會先按 "字段x" 排序; 在 "字段x" 的值相同時會按 "字段y" 排序; 在 "字段y" 的相同時...
IndexFIEldNames 沒有更多了, 更復雜的排序就需要建立排序對象(TIndexDef)了.
實現倒排序的例子:
{ 下面是在 holdings.XML 的基礎上建立的兩個索引; ACCT_NBR、SYMBOL 是其中的兩個字段 }
procedure TForm1.FormCreate(Sender: TObject);
begin
ClIEntDataSet1.AddIndex('Index_1', 'ACCT_NBR; SYMBOL', []); { 正序 }
ClIEntDataSet1.AddIndex('Index_2', 'ACCT_NBR; SYMBOL', [ixDescending]); { 倒序 }
ClIEntDataSet1.IndexName := 'Index_1';
end;
{ 切換上面建立的兩個索引 }
procedure TForm1.Button1Click(Sender: TObject);
begin
if ClIEntDataSet1.IndexName = 'Index_1' then
ClIEntDataSet1.IndexName := 'Index_2'
else
ClIEntDataSet1.IndexName := 'Index_1';
ClIEntDataSet1.First;
end;
{ 上面的 TForm1.FormCreate 過程也可以寫作(另一種建立方法) }
procedure TForm1.FormCreate(Sender: TObject);
begin
with ClIEntDataSet1.IndexDefs.AddIndexDef do
begin
Name := 'Index_1';
FIElds := 'ACCT_NBR; SYMBOL';
end;
with ClIEntDataSet1.IndexDefs.AddIndexDef do
begin
Name := 'Index_2';
FIElds := 'ACCT_NBR; SYMBOL';
Options := [ixDescending];
end;
ClIEntDataSet1.IndexName := 'Index_1';
end;
關於 AddIndex:
AddIndex(
const Name: string; { 索引名稱; 不能重名 }
const FIElds: string; { 索引字段; 多個字段用分號隔開; 默認升序排列 }
Options: TIndexOptions; { 選項 }
const DescFields, { 按降序排列的字段; 須先在 FIElds 中列出 }
const CaseInsFields: string; { 不區分大小寫的字段; 須先在 FIElds 中列出 }
const GroupingLevel: Integer { 分組級別, 用於分組統計的 }
);
//Options:
IxPrimary { 主索引 }
IxUnique { 字段值無重復 }
ixDescending { 降序 }
ixCaseInsensitive { 不區分大小寫 }
ixExpression { 無用 }
ixNonMaintained { 無用 }
{ 可選空值 [], 最多不能多於兩個選項 }
{ 若是兩個選項, 其中之一須是: ixDescending 或 ixCaseInsensitive }
AddIndex 的一些用法(都是先 F1 後 F2):
//F1、F2 降序, 兩種寫法一樣:
AddIndex('Index_1', 'F1; F2', [ixDescending]);
AddIndex('Index_2', 'F1; F2', [], 'F1; F2');
//F1、F2 不區分大小寫排序(不指定降序則默認升序):
AddIndex('Index_1', 'F1; F2', [ixCaseInsensitive]);
AddIndex('Index_2', 'F1; F2', [], '', 'F1; F2');
//F1 升序, F2 降序:
AddIndex('Index_1', 'F1; F2', [], 'F2');
AddIndex('Index_2', 'F1; F2', [ixDescending], 'F2'); { 此時 [ixDescending] 被忽略 }
//F1 降序, F2 升序:
AddIndex('Index_1', 'F1; F2', [], 'F1');
AddIndex('Index_2', 'F1; F2', [ixDescending], 'F1');
AddIndex 能做到的, 用 IndexDefs.AddIndexDef 也可以, 並且也都能在設計時完成.