📄 unitmain.pas
字号:
//则被关连表的这个记录的被关连字段值不允许修改,也不允许删除。
//如果说主键约束主要是保证字段值的唯一性的话,外键约束就是为了保存整个数据库数据的完整性。
//也就是说:InStoreDetail的商品编号字段不允许也不应该存在一个在Goods表中不存在的记录。
Except
On E:Exception do
begin
ShowMessage('创建触发器:ut_GoodInDetail_UDI出错,请检查网络连接是否正常!'+#13#10+
'错误信息:'+E.Message);
Raise;
end;
end;
end;
SQL.Clear;
SQL.Add('Select * from SysObjects Where Name="ut_GoodInDetail_UDI"');
Try
Open;
Except
On E:Exception do
begin
ShowMessage('打开系统数据表:SysObjects出错,请检查网络连接是否正常!'+#13#10+
'错误信息:'+E.Message);
Raise;
end;
end;
if IsEmpty then
begin
SQL.Clear;
SQL.Add('CREATE TRIGGER ut_GoodInDetail_UDI ON InStoreDetail FOR DELETE , INSERT , UPDATE AS');
//创建触发器。
SQL.Add('BEGIN');
SQL.Add(' DECLARE @INO_I VARCHAR (12) , @IGOODSNO_I INT , @ISTORENO_I INT , @FQUANTITY_I Numeric (8,2)');
SQL.Add(' DECLARE @INO_D VARCHAR (12) , @IGOODSNO_D INT , @ISTORENO_D INT , @FQUANTITY_D Numeric (8,2)');
//定义变量,在SQL中,所有的变量都用@作头。
SQL.Add(' UPDATE Storage Set fQuantity = 0 WHERE fQuantity IS NULL');
//将所以fQuantity字段为NULL的记录改成0。因为在SQL中,NULL无论与什么进行运算结果都是NULL。
SQL.Add(' DECLARE DELETED_CURSOR CURSOR FOR');
SQL.Add(' SELECT INO , IGoodsNo , fQuantity FROM DELETED;');
//定义游标。DELETED是SQL中的一个临时表,当删除一个或几个记录时这些被删除的记录都会放在这个临时表中
//如果是更新记录,则SQL会先将原来的数据放在DELETED临时表中,再将新的数据放在INSERTED临时表中。也就是说先删除,再增加。
SQL.Add(' OPEN DELETED_CURSOR');
//打开游标。
SQL.Add(' FETCH NEXT FROM DELETED_CURSOR INTO @INO_D , @IGOODSNO_D , @FQUANTITY_D');
//取游标的第一个记录。
SQL.Add(' WHILE @@FETCH_STATUS = 0');
//FETCH语句的结果。@@FETCH_STATUS在SQL中是一个全局变量,当FETCH从游标中正确取得一个记录就等于0/
SQL.Add(' BEGIN');
SQL.Add(' SET @ISTORENO_D = ( SELECT iStore FROM InStoreMaster WHERE INO = @INO_D )');
//取得仓库编号。
SQL.Add(' IF EXISTS(SELECT * FROM Storage WHERE iStoreNo = @ISTORENO_D AND IGoodsNo = @IGOODSNO_D)');
//如果仓库号/商品号在库存表中存在。
SQL.Add(' UPDATE Storage Set fQuantity = fQuantity - @FQUANTITY_D WHERE iStoreNo = @ISTORENO_D AND IGoodsNo = @IGOODSNO_D');
//就只更新库存数量。原库存减去数量。
SQL.Add(' ELSE');
SQL.Add(' INSERT INTO Storage (iStoreNo , iGoodsNo , fQuantity ) VALUES ( @ISTORENO_D , @IGOODSNO_D , - @FQUANTITY_D )');
//插入一条记录。
SQL.Add(' FETCH NEXT FROM DELETED_CURSOR INTO @INO_D , @IGOODSNO_D , @FQUANTITY_D');
//取下一条记录。
SQL.Add(' END');
SQL.Add(' CLOSE DELETED_CURSOR');
SQL.Add(' DEALLOCATE DELETED_CURSOR');
//关闭游标并释放资源。
SQL.Add(' DECLARE INSERTED_CURSOR CURSOR FOR');
SQL.Add(' SELECT INO , IGoodsNo , fQuantity FROM INSERTED;');
//定义游标。INSERTED是SQL中的一个临时表,当插入一个或几个记录时这些被插入的记录都会放在这个临时表中
//如果是更新记录,则SQL会先将原来的数据放在DELETED临时表中,再将新的数据放在INSERTED临时表中。也就是说先删除,再增加。
SQL.Add(' OPEN INSERTED_CURSOR');
//打开游标。
SQL.Add(' FETCH NEXT FROM INSERTED_CURSOR INTO @INO_I , @IGOODSNO_I , @FQUANTITY_I');
//取游标的第一个记录。
SQL.Add(' WHILE @@FETCH_STATUS = 0');
//FETCH语句的结果。@@FETCH_STATUS在SQL中是一个全局变量,当FETCH从游标中正确取得一个记录就等于0/
SQL.Add(' BEGIN');
SQL.Add(' SET @ISTORENO_I = ( SELECT iStore FROM InStoreMaster WHERE INO = @INO_I )');
//取得仓库编号。
SQL.Add(' IF EXISTS(SELECT * FROM Storage WHERE iStoreNo = @ISTORENO_I AND IGoodsNo = @IGOODSNO_I)');
//如果仓库号/商品号在库存表中存在。
SQL.Add(' UPDATE Storage Set fQuantity = fQuantity + @FQUANTITY_I WHERE iStoreNo = @ISTORENO_I AND IGoodsNo = @IGOODSNO_I');
//就只更新库存数量。原库存减去数量。
SQL.Add(' ELSE');
SQL.Add(' INSERT INTO Storage (iStoreNo , iGoodsNo , fQuantity ) VALUES ( @ISTORENO_I , @IGOODSNO_I , @FQUANTITY_I )');
//插入一条记录。
SQL.Add(' FETCH NEXT FROM INSERTED_CURSOR INTO @INO_I , @IGOODSNO_I , @FQUANTITY_I');
//取下一条记录。
SQL.Add(' END');
SQL.Add(' CLOSE INSERTED_CURSOR');
SQL.Add(' DEALLOCATE INSERTED_CURSOR');
//关闭游标并释放资源。
SQL.Add(' DELETE FROM Storage WHERE fQuantity = 0');
//删除库存数为0的记录。
SQL.Add('END');
ExecSQL;
end;
//以上是检查整个数库的表是否完整。
finally
Free;
end;
end;
Except
Result:=False;
end;
end;
constructor TFormMain.Create(AOwner: TComponent);
function ComputerName : String;
var
CNameBuffer : PChar;
fl_loaded : Boolean;
CLen : ^DWord;
begin
GetMem(CNameBuffer,255);
New(CLen);
CLen^:= 255;
fl_loaded := GetComputerName(CNameBuffer,CLen^);
if fl_loaded then
Result := StrPas(CNameBuffer)
//转换PChar到String。
else
Result := '';
FreeMem(CNameBuffer,255);
Dispose(CLen);
end;
begin
MainFormCreated:=True;
FormDataBaseInfo:=TFormDataBaseInfo.Create(Application);
try
FormDataBaseInfo.EditServerName.Text:=ComputerName;
if FormDataBaseInfo.ShowModal=mrOK then
begin
Application.ProcessMessages;
UserName:=FormDataBaseInfo.EditUserName.Text;
Password:=FormDataBaseInfo.EditPassword.Text;
ServerName:=FormDataBaseInfo.EditServerName.Text;
with TDatabase.Create(Application) do
begin
Try
DatabaseName:='TestDatabase';
//随便给DatabaseName命个名字就可以了。
LoginPrompt:=False;
DriverName:='MSSQL';
//这行是关闭TDatabase内置的登录对话框。
Params.Clear;
Params.Add('Server Name='+ServerName);
Params.Add('Database Name=MASTER');
Params.Add('User Name='+UserName);
Params.Add('Password='+Password);
Try
FormFlash.Panel1.Caption:='打开数据库。。。';
Application.ProcessMessages;
Open;//尝试打开数据库,如果正常打开,则说明SQL服务器工作正常,并且用户名和密码正确。
With TQuery.Create(Application) do
begin
try
DatabaseName:='TestDatabase';
SQL.Add('Select * from Sysdatabases Where Name="TestDB"');
try
FormFlash.Panel1.Caption:='查找数据库。。。';
Application.ProcessMessages;
Open;
Except
On E:Exception do
begin
Application.MessageBox(PChar('不能打开MASTER数据库的Sysdatabases表,请确认是否有打开该表的权限。'+#13#10#13#10+
'错误信息:'+E.Message),'提示:',MB_ICONERROR);
MainFormCreated:=False;
end;
end;
if MainFormCreated and IsEmpty then//如果返回为空则表示TestDB还没有创建。
begin
//SQL Server所有的用户数据库都在Master数据库的Sysdatabases表中有记录。
Close;
SQL.Clear;
SQL.Add('Create Database TestDB');
try
FormFlash.Panel1.Caption:='创建数据库。。。';
Application.ProcessMessages;
ExecSQL;
//这里用ExecSQL而不是用Open,是因为DataSet的Open方法只是用于打开SQL语是Select语句的返回结果集
//对于其它SQL语句因为没有返回集所以只能用ExecSQL来执行。
Except
On E:Exception do
begin
Application.MessageBox(PChar('不能创建数据库,请确认是否有创建数据库的权限。'+#13#10#13#10+
'错误信息:'+E.Message),'提示:',MB_ICONERROR);
MainFormCreated:=False;
end;
end;
end;
finally
Free;
end;
end;
Except
on E:exception do
begin
Application.MessageBox(PChar('不能打开数据库,请确认网络联接正常并稍后再试。'+#13#10#13#10+
'错误信息:'+E.Message),'提示:',MB_ICONERROR);
MainFormCreated:=False;
end;
end;
finally
Free;
end;
end;
end else
begin
MainFormCreated:=False;
Application.Terminate;//强行中止系统。
end;
finally
FormDataBaseInfo.Free;
end;
//以上代码尝试用用户输入的密码和用户名打开指定的数据库。如果打开正常,则保存输入的信息到全局变量并进入系统,否则退出。
if MainFormCreated then
begin
inherited Create(AOwner);
//重用父类TForm的构造函数Create。
With Database1 do
begin
Database1.Close;
DriverName:='MSSQL';
DatabaseName:='TestDatabase';
//随便给DatabaseName命个名字就可以了。
LoginPrompt:=False;
//这行是关闭TDatabase内置的登录对话框。
Params.Clear;
Params.Add('Server Name='+ServerName);
Params.Add('Database Name=TestDB');
Params.Add('User Name='+UserName);
Params.Add('Password='+Password);
FormFlash.Panel1.Caption:='连接数据库。。。';
Application.ProcessMessages;
Open;
end;
end else
Application.Terminate;
end;
procedure TFormMain.ItemExitClick(Sender: TObject);
begin
Close;
end;
Function TFormMain.ChildFormExists(FormName:String):Boolean;
Var i:Integer;
begin
Result:=False;
For i:=0 to MDIChildCount-1 do
begin
if MDIChildren[i].Name=FormName then
begin
MDIChildren[i].WindowState:=wsMaximized;
Result:=True;
//如果Form已经存在,就显示它
Break;
end;
end;
end;
procedure TFormMain.ItemInStoreClick(Sender: TObject);
begin
if not ChildFormExists('FormInStore') then
FormInStore:=TFormInStore.Create(Self);
//如果不存在就创建它。
end;
procedure TFormMain.ItemEmployeeClick(Sender: TObject);
begin
if not ChildFormExists('FormEmployee') then
FormEmployee:=TFormEmployee.Create(Self);
//如果不存在就创建它。
end;
procedure TFormMain.ItemStoreClick(Sender: TObject);
begin
if not ChildFormExists('FormStore') then
FormStore:=TFormStore.Create(Self);
//如果不存在就创建它。
end;
procedure TFormMain.ItemGoodsClick(Sender: TObject);
begin
if not ChildFormExists('FormGoods') then
FormGoods:=TFormGoods.Create(Self);
//如果不存在就创建它。
end;
procedure TFormMain.ItemStorageClick(Sender: TObject);
begin
if not ChildFormExists('FormStorage') then
FormStorage:=TFormStorage.Create(Self);
//如果不存在就创建它。
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -