sqlite 日期加减(11.Lazarus数据库编程8.ZeosDBO与SQLite3综合示例)
sqlite 日期加减(11.Lazarus数据库编程8.ZeosDBO与SQLite3综合示例)数据模块组件如下图所示:表单窗体界面设计:以上 SQL 语句可以使用 DBeaver 等数据库管理工具连接到 SQLite3 数据库上执行。需求描述:通过主界面展现表中的数据,可以实现新增、修改和删除,新增和修改数据时,部门数据作为选项,在表单界面中可以选择,学历也可以进行选择,不过,选项数据是固定的。主窗体界面设计:
8.ZeosDBO与SQLite3综合示例本节将使用 ZeosDBO 与 SQLite3 数据完成一个数据库表 CRUD 的示例,数据表结构及数据如下:
create table c_dep (
    dep_id varchar(64) primary key 
    dep_name varchar(16)
);
insert into c_dep (dep_id  dep_name)
values ('yfb'  '研发部');
insert into c_dep (dep_id  dep_name)
values ('xsb'  '销售部');
insert into c_dep (dep_id  dep_name)
values ('jszcb'  '技术支持部');
insert into c_dep (dep_id  dep_name)
values ('cwb'  '财务部');
insert into c_dep (dep_id  dep_name)
values ('xzb'  '行政部');
create table d_dep_staff (
    staff_id varchar(64) primary key 
    dep_id varchar(64) 
    name varchar(32) 
    sex varchar(8) 
    birthday date 
    edu_level varchar(16) 
    school varchar(64) 
    speciality varchar(32) 
    native_place varchar(256)
);
INSERT INTO d_dep_staff
(staff_id  dep_id  name  sex  birthday  edu_level  school  speciality  native_place)
VALUES(hex(randomblob(16))  'yfb'  '张三'  '女'  '1981-9-10'  '本科'  '内蒙古大学'  '经济管理'  '内蒙古乌兰察布市集宁区');
INSERT INTO d_dep_staff
(staff_id  dep_id  name  sex  birthday  edu_level  school  speciality  native_place)
VALUES(hex(randomblob(16))  'xsb'  '刘五'  '男'  '1978-7-11'  '本科'  '内蒙古大学'  '计算机科学与技术'  '内蒙古鄂尔多斯市东胜区');
INSERT INTO d_dep_staff
(staff_id  dep_id  name  sex  birthday  edu_level  school  speciality  native_place)
VALUES(hex(randomblob(16))  'xzb'  '弓九'  '女'  '1983-3-10'  '本科'  '内蒙古科技大学'  '计算机科学与技术'  '内蒙古呼和浩特市托克托县');
    
在上面的数据表设计中,表的主键采用了字符串类型,一般情况下,我会考虑使用 UUID 来填充。UUID(Universal Unique Identifier)或者 GUID(Globally Unique Identifier)是一个 128 比特的数字,可以用于唯一标识每个网络对象或资源。由于它的生成机制,一个 UUID 可以保证几乎不会与其他 UUID 重复,因此常常用于生成数据库中的主键值。
SQLite 提供了一个 randomblob(N) 函数,可以用于返回一个 N 字节的伪随机字节 BLOB。利用该函数和 hex() 函数可以返回 GUID:
SELECT hex(randomblob(16)) AS guid;
guid                            |
--------------------------------|
BEA6B419172B9FAECE45883D13935690|
    
在上面数据表 d_dep_staff 的 Insert 语句中使用了该方法生成 UUID。
以上 SQL 语句可以使用 DBeaver 等数据库管理工具连接到 SQLite3 数据库上执行。
8.1 需求描述及界面设计需求描述:通过主界面展现表中的数据,可以实现新增、修改和删除,新增和修改数据时,部门数据作为选项,在表单界面中可以选择,学历也可以进行选择,不过,选项数据是固定的。
主窗体界面设计:

表单窗体界面设计:

数据模块组件如下图所示:

组件属性:
| 
     组件  | 
     属性  | 
     值  | 
| 
     ZConnection1  | 
     Protocol  | 
     SQLite-3  | 
| 
     Database  | 
     E:\workspace_of_lazarus\demodb.db  | |
| 
     Connected  | 
     True  | |
| 
     ZReadOnlyQuery1  | 
     Connection  | 
     ZConnection1  | 
| 
     SQL  | 
     SELECT staff_id s.dep_id name sex birthday edu_level school speciality native_place d.dep_name FROM d_dep_staff s left join c_dep d on s.dep_id = d.dep_id  | |
| 
     Active  | 
     True  | 
数据组件声明代码:
TDataModule1 = class(TDataModule)
    ZConnection1: TZConnection;
    ZReadOnlyQuery1: TZReadOnlyQuery;
    // 字段
    ZReadOnlyQuery1_birthday: TDateField;
    ZReadOnlyQuery1_dep_id: TStringField;
    ZReadOnlyQuery1_dep_name: TStringField;
    ZReadOnlyQuery1_edu_level: TStringField;
    ZReadOnlyQuery1_name: TStringField;
    ZReadOnlyQuery1_native_place: TStringField;
    ZReadOnlyQuery1_school: TStringField;
    ZReadOnlyQuery1_sex: TStringField;
    ZReadOnlyQuery1_speciality: TStringField;
    ZReadOnlyQuery1_staff_id: TStringField;
  private
  public
  end;       8.2.2 主窗体
    
主窗体组件如下图所示:

组件属性:
| 
     组件  | 
     属性  | 
     值  | 
| 
     DataSource1  | 
     DataSet  | 
     DataModule1.ZReadOnlyQuery1  | 
| 
     DBNavigator1  | 
     DataSource  | 
     DataSource1  | 
| 
     VisibleButtons  | 
     [nbFirst nbPrior nbNext nbLast]  | |
| 
     Align  | 
     alRight  | |
| 
     DBGrid1  | 
     DataSource  | 
     DataSource1  | 
| 
     Options  | 
     dgRowSelect=True  | |
| 
     Align  | 
     alClient  | 
主窗体声明代码:
TForm1 = class(TForm)
    // 按钮
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    // 数据库组件
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    // 容器 - 放置按钮和数据导航组件
    Panel1: TPanel;
    
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure DBGrid1DblClick(Sender: TObject);
  private
  public
  end;       8.2.3 表单窗体
    
表单窗体如下图所示:

表单窗体的声明代码:
TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    // 数据编辑控件
    DepComboBox: TComboBox;
    GroupBox7: TGroupBox;
    NativePlaceEdit: TEdit;
    SpecialityEdit: TEdit;
    SchoolEdit: TEdit;
    EduLevelComboBox: TComboBox;
    NameEdit: TEdit;
    SexRadioGroup: TRadioGroup;
    BirthdayDateTimePicker: TDateTimePicker;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    GroupBox3: TGroupBox;
    GroupBox4: TGroupBox;
    GroupBox5: TGroupBox;
    GroupBox6: TGroupBox;
 
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormActivate(Sender: TObject);
  private
  public
    isNew: Boolean;
  end;             8.3 功能实现代码8.3.1 主窗体功能代码
    
各部分功能代码与上一节《【11.Lazarus数据库编程】7.ZeosDBO Database CRUD》内容基本相同,在这里就不赘述了,有兴趣的读者可以阅读一下上一节内容。
procedure TForm1.Button1Click(Sender: TObject);
begin
  // 新建
  Form2.isNew := True;
  if Form2.ShowModal = mrOk then
  begin
    DataModule1.ZReadOnlyQuery1.Refresh;
  end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  // 编辑
  if DataModule1.ZReadOnlyQuery1.BOF then
    if DataModule1.ZReadOnlyQuery1.RecordCount > 0 then
      DataModule1.ZReadOnlyQuery1.First
    else
      Exit;
  if DataModule1.ZReadOnlyQuery1.EOF then
    if DataModule1.ZReadOnlyQuery1.RecordCount > 0 then
      DataModule1.ZReadOnlyQuery1.Last
    else
      Exit;
  Form2.isNew := False;
  if Form2.ShowModal = mrOk then
  begin
    DataModule1.ZReadOnlyQuery1.Refresh;
  end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
  Query: TZQuery;
begin
  // 删除
  if DataModule1.ZReadOnlyQuery1.BOF then
    if DataModule1.ZReadOnlyQuery1.RecordCount > 0 then
      DataModule1.ZReadOnlyQuery1.First
    else
      Exit;
  if DataModule1.ZReadOnlyQuery1.EOF then
    if DataModule1.ZReadOnlyQuery1.RecordCount > 0 then
      DataModule1.ZReadOnlyQuery1.Last
    else
      Exit;
  Query := TZQuery.Create(Self);
  try
    Query.Connection := DataModule1.ZConnection1;
    Query.Close;
    Query.SQL.Text := 'DELETE FROM d_dep_staff where staff_id = :staffId';
    Query.Params.ParamByName('staffId').AsString := DataModule1.ZReadOnlyQuery1_staff_id.Value;
    Query.ExecSQL;
  except
      on D: EDatabaseError do
         MessageDlg('Error'  'A database error has occurred. Technical error message: '   D.Message  mtError  [mbOK]  0);
  end;
  Query.Destroy;
  DataModule1.ZReadOnlyQuery1.Refresh;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
  // 刷新
  DataModule1.ZReadOnlyQuery1.Refresh;
end;
procedure TForm1.DBGrid1DblClick(Sender: TObject);
begin
  Button2Click(Sender);
end;                 8.3.2 表单窗体功能代码
    
各部分功能代码与上一节《【11.Lazarus数据库编程】7.ZeosDBO Database CRUD》内容基本相同,在这里就不赘述了,有兴趣的读者可以阅读一下上一节内容。
procedure TForm2.Button1Click(Sender: TObject);
begin
  // 取消
  ModalResult := mrCancel;
end;
procedure TForm2.Button2Click(Sender: TObject);
var
  Query: TZQuery;
  index: Integer;
  depId: String;
begin
  // 确定
  if NameEdit.Text = '' then
  begin
    MessageDlg('提示'  '请输入姓名!'  mtError  [mbOK]  0);
    Exit;
  end;
  if DepComboBox.ItemIndex < 0 then
  begin
    MessageDlg('提示'  '请选择所在部门!'  mtError  [mbOK]  0);
    Exit;
  end;
  index := DepComboBox.ItemIndex;
  depId := PAnsiString(DepComboBox.Items.Objects[index])^;
  Query := TZQuery.Create(Self);
  try
    Query.Connection := DataModule1.ZConnection1;
    Query.Close;
    if isNew then
    begin
      Query.SQL.Text := 'INSERT INTO d_dep_staff (staff_id  dep_id  name  sex  birthday  edu_level  school  speciality  native_place) VALUES(hex(randomblob(16))  :depId  :name  :sex  :birthday  :eduLevel  :school  :speciality  :nativePlace)';
      Query.Params.ParamByName('depId').AsString := depId;
      Query.Params.ParamByName('name').AsString := NameEdit.Text;
      if SexRadioGroup.ItemIndex = 0 then
        Query.Params.ParamByName('sex').AsString := '男'
      else
        Query.Params.ParamByName('sex').AsString := '女';
      Query.Params.ParamByName('birthday').AsDate := BirthdayDateTimePicker.Date;
      Query.Params.ParamByName('eduLevel').AsString := EduLevelComboBox.Text;
      Query.Params.ParamByName('school').AsString := SchoolEdit.Text;
      Query.Params.ParamByName('speciality').AsString := SpecialityEdit.Text;
      Query.Params.ParamByName('nativePlace').AsString := NativePlaceEdit.Text;
      Query.ExecSQL;
    end
    else
    begin
      Query.SQL.Text := 'UPDATE d_dep_staff SET dep_id=:depId  name=:name  sex=:sex  birthday=:birthday  edu_level=:eduLevel  school=:school  speciality=:speciality  native_place=:nativePlace WHERE staff_id=:staffId';
      Query.Params.ParamByName('depId').AsString := depId;
      Query.Params.ParamByName('name').AsString := NameEdit.Text;
      if SexRadioGroup.ItemIndex = 0 then
        Query.Params.ParamByName('sex').AsString := '男'
      else
        Query.Params.ParamByName('sex').AsString := '女';
      Query.Params.ParamByName('birthday').AsDate := BirthdayDateTimePicker.Date;
      Query.Params.ParamByName('eduLevel').AsString := EduLevelComboBox.Text;
      Query.Params.ParamByName('school').AsString := SchoolEdit.Text;
      Query.Params.ParamByName('speciality').AsString := SpecialityEdit.Text;
      Query.Params.ParamByName('nativePlace').AsString := NativePlaceEdit.Text;
      Query.Params.ParamByName('staffId').AsString := DataModule1.ZReadOnlyQuery1_staff_id.Value;
      Query.ExecSQL;
    end;
  except
      on D: EDatabaseError do
         MessageDlg('Error'  'A database error has occurred. Technical error message: '   D.Message  mtError  [mbOK]  0);
  end;
  Query.Destroy;
  ModalResult := mrOk;
end;
procedure TForm2.FormActivate(Sender: TObject);
var
  Query: TZQuery;
  index: Integer;
begin
  // 初始化部门选项
  try
    Query := TZQuery.Create(Self);
    Query.Connection := DataModule1.ZConnection1;
    Query.Close;
    Query.SQL.Text := 'SELECT dep_id  dep_name FROM c_dep';
    Query.Open;
    DepComboBox.Items.Clear;
    while not Query.EOF do
    begin
      DepComboBox.Items.AddObject(
        Query.FieldByName('dep_name').AsString 
        TObject(NewStr(Query.FieldByName('dep_id').AsString))
      );
      Query.Next;
    end;
  except
      on D: EDatabaseError do
         MessageDlg('Error'  'A database error has occurred. Technical error message: '   D.Message  mtError  [mbOK]  0);
  end;
  // 初始化数据项
  if isNew then
  begin
    NameEdit.Text:='';
    SexRadioGroup.ItemIndex:=0;
    SchoolEdit.Text:='';
    SpecialityEdit.Text:='';
    NativePlaceEdit.Text:='';
  end
  else
  with DataModule1 do
  begin
    NameEdit.Text:=ZReadOnlyQuery1_name.Value;
    if ZReadOnlyQuery1_sex.Value = '男' then
      SexRadioGroup.ItemIndex:=0
    else
      SexRadioGroup.ItemIndex:=1;
    index := DepComboBox.Items.IndexOf(ZReadOnlyQuery1_dep_name.Value);
    DepComboBox.ItemIndex:=index;
    BirthdayDateTimePicker.Date := ZReadOnlyQuery1_birthday.Value;
    EduLevelComboBox.Text := ZReadOnlyQuery1_edu_level.Value;
    SchoolEdit.Text := ZReadOnlyQuery1_school.Value;
    SpecialityEdit.Text:=ZReadOnlyQuery1_speciality.Value;
    NativePlaceEdit.Text:= ZReadOnlyQuery1_native_place.Value;
  end;
end;           
    




