使用Delphi+MSSQL实现多物料进出仓

 

前几天写了关于单物料进出仓的存储过程,现在要求从Delphi 7编写的Client端可以同时操作多物料进仓,也就是说可以从客户端一次向数据库提交多条记录。

  在这个题目中,有人采用了在数据库中建立临时表,每次在客户端增加一条记录,就将这条记录提交到临时表,输入结束后,通过调用SQL SERVER 中的存储过程将临时表中的记录再转到正式表中。这种办法可行,但是每增加一条记录,都需将记录先送入临时表,这样就需要访问一次数据库,无疑增加了客户端和数据库之间的通信量,造成不必要的浪费。

  但是,由于SQL SERVER不能接受数组参数,所以无法在Client端将多条记录用数组形式提交到SQL SERVER 的存储过程,这时可以使用一种变通的办法。

  由于 SQL SERVER 有强大的字符串处理能力,因此可以将输入的多条进出仓记录在Client以一定得格式组织成字符串,然后使用SQL SERVER 中的字符串处理功能将提交的字符串再一次分割成独立的记录,供进出仓操作。    

  以下是具体的实现。
  首先建立一个视图:
create view multigio
as
      select j060230gtb.gid,j060230gtb.gname,j060230gtb.gunit,j060230giotb.iosize,j060230giotb.iomoney,j060230giotb.remarks,j060230giotb.iodate,j060230utb.uid from j060230utb,j060230gtb,j060230giotb
where 1=2

  该视图用来在Client端使用ADOTable生成一个包含所需参数的空表(之所以是空表是因为where 1=2)。为了能直观的看到输入的结果,再添加一个TDBGrid组件,将其和ADOTable组件关联。设置ADOTable不自动提交更新,否则就出错了,因为它对应的是一个多张表连接得到视图,这个ADOTable只是用来暂存数据的,里头的数据是永远不送到数据库的。

  进出仓记录添加完成后,通过循环将ADOTable的记录按行循环读出,每个字段之间用指定的符号分割(本例使用的是键盘TAB键上面的那个'`'),记录之间用不同的分隔符,本例使用分号";",连接成一个字符串。然后调用指定的存储过程,将这个字符串作为参数。Delphi代码如下:

if RbtnMulti.Checked = true then //多物料
  begin
      //构造字符串
      rec_set := '';
      DBGridTmpView.DataSource.DataSet.First;
      if DBGridTmpView.DataSource.DataSet.FieldByName('gid').AsString = '' then
      begin
          showmessage('请输入信息!');
          exit;
      end;
      while not DBGridTmpView.DataSource.DataSet.eof do
      begin
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('gid').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('gname').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('gunit').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('iosize').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('iomoney').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('iodate').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('remarks').AsString + '`';
        rec_set := rec_set + DBGridTmpView.DataSource.DataSet.FieldByName('uid').AsString + '`';
        rec_set := rec_set + ';';
        DBGridTmpView.DataSource.DataSet.Next;
      end;
      //showmessage(rec_set);
      with DataMo.ADOSProcMGio do
      begin
        close;
        Parameters.ParamByName('@m_rec_set').Value := rec_set;
        if RbtnPush.Checked = true then
         Parameters.ParamByName('@m_iomark').Value := '1'
        else
         Parameters.ParamByName('@m_iomark').Value := '0';
        Parameters.ParamByName('@m_stat').Value := '';
        Parameters.ParamByName('@m_msg').Value := '';
        execProc;
        pmsg := Parameters.ParamByName('@m_stat').Value;
        billno := Parameters.ParamByName('@m_msg').Value;
        showmessage(pmsg+ ' 单号:' + billno);
        RbtnSingle.Checked := true;
        RefreshTables(billno,'');
      end;
  end;

  通过以上代码可以将输入连接成符合存储过程切分需要格式的字符串,并且执行进出仓的操作,里头的RefreshTables()函数是自定义的。

  一下是具体的存储过程代码:

--drop proc ProcMultiGio
/*-----------------------多物料进出仓-------------------------*/
/*该存储过程使用";"(分号)做记录分割符,使用"`"(TAB键上面的键)做字段分割符*/
create proc ProcMultiGio
    @m_rec_set varchar(2000),     --客户端提交的总集合
    @m_iomark char(1),              --进出标志
    @m_stat varchar(30) output,   --返回状态
    @m_msg varchar(10) output     --成功返回单号
  as
  declare
      --内部字段参数
      @m_gid char(4),             --1、物料代码
      @m_gname varchar(20),       --2、物料名称
      @m_gunit varchar(8),        --3、物料计量单位
      @m_iosize numeric(10,2),    --4、进出数量
      @m_iomoney numeric(10,2),   --5、进出钱数
      @m_iodate datetime,         --6、进出日期
      @m_remarks varchar(60),     --7、备注信息
      @m_uid char(4),             --8、操作人员代码
      --内部中间量
      @m_billno char(10),         --单号
      @rowpoint int,              --行分割符索引
      @colpoint int,              --列分割符索引
      @eachrow char (200),        --分割出来的整行
      @m_storesize numeric(10,2), --库存量
      @p_space  varchar(2),       --填充
      @p_now    varchar(12)       --时间串
  begin transaction  --启动事务
   /*生成单号*/
   set @m_billno = (select top 1 billno from j060230giotb order by bid desc);/*获取最后一个单号*/
  
   if @m_billno IS NULL
     set @m_billno = 'S000000000';
  
   set @m_billno = substring(@m_billno,8,3);
   set @m_billno = convert(varchar(10),(cast(@m_billno as int) + 1));
   set @p_space = replace(space(3-len(@m_billno)),' ','0');
   set @p_now = (SELECT stuff(replace(CAST(GETDATE() AS CHAR(10)),' ',''),5,2,''));
   set @m_billno = 'T' + @p_now + @p_space + @m_billno; /*形成最终单号 进出标志+时间+填充0 + 编号*/
   /*单号生成完成*/
  
   /*进行字符串的拆分*/
   while len(@m_rec_set) > 0  --循环进行记录分割
   begin
      select @rowpoint = charindex(';',@m_rec_set) --读第一个记录分割符的字符串索引
      select @eachrow  = substring(@m_rec_set,1,@rowpoint-1) --取出一条记录
      select @m_rec_set = substring(@m_rec_set,@rowpoint+1,len(@m_rec_set)-@rowpoint) --从记录集合中删除读过的记录
      
      if len(@eachrow) > 0 --还有记录,对行进行字段分割,将个值赋予每个字段参数
      begin
  --取第一个字段gid->@m_gid
         select @colpoint   = charindex('`',@eachrow) --第一字段末尾
         select @m_gid      = substring(@eachrow,1,@colpoint-1) --去第一个字段
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint) --取剩下的字符串
        
         -- 取第二个字段gname->@m_gname
         select @colpoint   = charindex('`',@eachrow)
         select @m_gname    = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
         --取第三个字段gunit->@m_gunit
         select @colpoint   = charindex('`',@eachrow)
         select @m_gunit    = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
         --取第四个字段iosize->@m_iosize
         select @colpoint   = charindex('`',@eachrow)
         select @m_iosize   = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
         --取第五个字段iomoney->@m_iomoney
         select @colpoint   = charindex('`',@eachrow)
         select @m_iomoney  = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
         --取第六个字段iodate->@m_iodate
         select @colpoint   = charindex('`',@eachrow)
         select @m_iodate   = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
         --取第七个字段remarks->@m_remarks
         select @colpoint   = charindex('`',@eachrow)
         select @m_remarks  = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
         --取第八个字段uid->@m_uid
         select @colpoint   = charindex('`',@eachrow)
         select @m_uid      = substring(@eachrow,1,@colpoint-1)
         select @eachrow    = substring(@eachrow,@colpoint+1,len(@eachrow)-@colpoint)
        
         --以下根据取得的参数判断进出仓操作
         if @m_iomark = '1'  --if input
         ---------进仓--------------------
         begin
           if exists (select gid from j060230gtb where gid=@m_gid)  /*判断是否物料是否存在*/
               update j060230gtb set gsize=gsize+@m_iosize where gid=@m_gid; /*存在就更新物料的库存数量*/
           else
               insert into j060230gtb (gid,gname,gsize,gunit) values (@m_gid,@m_gname,@m_iosize,@m_gunit); /*不存在先添加物料到物料表*/
          
           insert into j060230giotb (billno,gid,iosize,iomark,iomoney,remarks,uid,iodate)  /*将进仓信息进表*/
                              values(@m_billno,@m_gid,@m_iosize,'1',@m_iomoney,@m_remarks,@m_uid,@m_iodate)          
         end   --end if input
         ---------进仓------------------

         if @m_iomark = '0'  --if output
         ---------出仓------------------
         begin
           if not exists (select gid from j060230gtb where gid=@m_gid)  /*判断是否物料是否存在*/
           begin --物料不存在
            select @m_stat = @m_gid + '物料不存在!出库失败!'
            select @m_msg  = '无'
            rollback transaction  --事务回滚
            return --结束存储过程
           end
          
           --物料存在
           set @m_storesize =(select gsize from j060230gtb where gid=@m_gid) --读库存量
           if @m_storesize < @m_iosize --不够出
           begin
             select @m_stat = @m_gid +'库存不足,出库失败!'
             select @m_msg  = '无'
             rollback transaction     --事务回滚
             return  --结束存储过程
           end
          
           --满足出仓条件  
           update j060230gtb set gsize=gsize-@m_iosize where gid=@m_gid   --存在就更新物料的库存数量
           -- set @m_stat = '出库成功!'    
           insert into j060230giotb (billno,gid,iosize,iomark,iomoney,remarks,uid,iodate)  /*将出仓信息进表*/
                              values(@m_billno,@m_gid,@m_iosize,'0',@m_iomoney,@m_remarks,@m_uid,@m_iodate)
           --select @m_msg = @m_billno
          
         end  --end if output          
         ---------出仓--------------------
      end --end if

   end --end while
  
  select @m_stat = '操作成功!'
  select @m_msg  = @m_billno
  commit transaction  --end transaction
go
/*-----------------多物料进出仓----------------------------*/

这个存储过程完成了记录的切分和进出仓的操作。

到此多物料进出仓就完成了。

补充:
前一次单物料和这次的多物料共同的缺陷在于生成单号的地方。两次所使用的单号生成方法是相同的,但是这种方法的原理是读最后的单号,生成本次的单号。如果考虑到并发,这种的问题是显而易见的,非常容易出错。因此,这个问题需要采用另外的办法解决,考虑到与本文无关,这里不详细写。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实验课题二、简单物料/出信息管理 企业物料进出的信息管理物料进出的信息主要包括进出单号、进出日期、操作人员代码、备注、物料代码、进数量、出数量等 1.企业进出信息表以“班级+座号+(表示程序名的中英文信息)”来命名,可以用一个表,也可以用二个表(一对多关系),具体表设计的思路须在报告中描述。 2.进程序与出程序可以合并,也可以分开做,名称以“班级+座号+(表示程序名的中英文信息)”来命名。其中操作人员必须用下拉框来选择;单号要自己编规则自动生成,单号产生规则在报告中说明;进出日期用日期控件;物料代码必须下拉框做选择;当物料时必须判断出数量时候超过物料的库存数量,物料的库存数量在物料表中可以获得该物料的库存数量。进行进或出操作时必须通过调用存储过程来实现存储过程将操作结果返回调用者,显示成功或失败的信息。 3.进、出存储过程可以合并或分开做,存储过程名称以“班级+座号+(表示程序名的中英文信息)”来命名,存储过程要判断物料是否存在,操作后物料库存数量是否不为负数;如果不满足条件显示,失败提示;如果满足条件,增加进出表记录一条,并根据进出物料的数量对物料表中库存数量进行修改,提交数据库操作,否则回滚。 4.进出单查询程序,以“班级+座号+(表示程序名的中英文信息)”来命名,可以用进出日期起止条件,物料代码、操作人员、备注(用子串查询)来完成。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值