你从原表中滤出数据的时间和直接在原表中处理的时间差不了多少。
对原表中关键字段(cgddh,key_id, cbh)加组合索引,
并对原表建触发器对ytfwh表进行修改,不就很快了?

解决方案 »

  1.   

    Ytfwh表 怎么和cgddmxb  对应?添加Ytfwh表时whbh怎么取值?
      

  2.   

    ,(首先要把在cgddmxb中的
    whbh+cbh对应的ytfwh表里的whbh+cbh的这条记录sl的 值 减去cgddmxb中的
    这条记录的sl的值) cgddmxb表中没有whbh啊?你好好读读你的问题,确认没有逻辑错误再发上来
      

  3.   

    是的! 谢谢你,我想这个问题思路没有完全表达得很清楚。一定把您给气死了。1。ytfwh是一个仓库表(主键为 whbh+cbh)
    字段内容为
    whbh (仓库编号,int(4)), cbh(产品编号,char(10)), sl(库存量,float(8))2.cgddmxb(采购订单明细表) (主键为cgdh+key_id+cbh)
    表字段
    cgdh(单号,char(18)) ,key_id(序号,int(4)),cbh(产品编号,char(10)),sl(数量,float(8))3.#cgddmxb和cgddmxb的结构完全一样, 建这个表的目的就是先把cgddmxb里的内容调出到#cgddmxb里改,改完之后再 修改回去。问题: 每次针对#cgddmxb的修改 以whbh(我在程序通过一个combobox让用户选择)+cbh的数量sl 都会添加或者修改到仓库ytfwh表里对应的whbh+cbh。
      

  4.   

    cgddmxb中没有whbh字段, 这个字段是通过combobox让用户选择得到的动态编号
    在程序通过:whbh传给存储过程可以吧
      

  5.   

    因为有很多公用的模块, 但就是表名不同,如cgddmxb,ctdmxb,都是明细表。结构都是一样的都,就表名,选择的仓库不同。还有单号名不同
    cgddmxb
    cddh,cbh, key_idcgthmxb
    ctdh, cbh, key_id
    所以存储过程只要给存储过程传表名 cgddmxb/cgthmxb, cddh/ctdh/, whbh
    三个参数。
    不知道我的想法有没有问题。请您指点。
    我想因为很多模块都涉及到对 ytfwh仓库表的sl进增加、修改。 但不删除这个表的数据。是不能删除ytfwh表的数据
      

  6.   

    有问题!
    一、你为什么要将cgddmxb的数据调到#cgddmxb修改?
    二、你修改的时候是将所有的数据导到#cgddmxb,还是有条件的导?
    三、修改完后,你凭什么来判断数据已修改?是将#cgddmxb与cgddmxb对比,还是根据#cgddmxb本身的变化?(而临时表是不能建触发器的!)如果将#cgddmxb与cgddmxb两表对比,万一在修改的时候别人也修改了怎么办?将他的修改改回去???
    总之我觉得你的设计不是很合理。若可以,你把你的设计来龙去脉的表达出来,发消息给我也可以,我再帮你参考一下。不过今天不行了。
      

  7.   

    一个晚上上不来。
     Chiff(~o~) 说得太对了,这种做法问题多多。整个处理思路要重新整理一下。
      

  8.   

    你问得非常好。其实这些都是我应该描述的。
    2。是有条件的导到#cgddmxb,
    我修改的时候是根据cgddmxb的cgdh为过滤条件,也就是cgdh='2002-02-01-0001'作为条件来修改的。 cgddmxb明细表对应的还有一个
    cgdd主表。 也就是当cgdd主表移动记录的时候,我把cgddmxb的内容调出到
    #cgddmxb来改,改完后再写回去3.在程序里修改的时候,如果有增加、删除、修改 #cgddmxb的记录的时候就会触发相应的ondelete,oninsert这些事件,就表示修改过了。
    4.是将#cgddmxb与cgddmxb表的内容作对比的。如果#cgddmxb中有明细记录修改了(以cddh+key_id+cbh作为唯一标识这条记录,) 如果不同了,就表示有修改过。
    5。 万一在修改的时候别人也修改了怎么办。
    这个问题我是这么解决的。
    在根据cgdd表的cgdh过涉世cgddmxb表内容的时候,把过滤的内容,一份存入
    #cgddmxb,另一份存入 #cgddmxb1(这个表和#cgddmxb的结构也是一模一样的).如果在保存的时候,再把cgddmxb 表对应的cgdh相应的记录过滤出来和#cgddmxb1的内容作对比,只要有一个字段的内容不相同, 就表示。在我修改的过程中有其它用户修改过, 回滚事务。
      

  9.   

    1.cgddmxb的内容随着时间,就会越来越多,所以只过滤出当前cgddmxb的cgdh=主表的.cgdh的记录。还要补充一下,因为我限定了在#cgddmxb临时表最多也只能是一百条记录。也就是
    key_id从1..100
      

  10.   

    create procedure xxx
    @cgddh date,@key_id int,@cbh int,@sl int,@dj int,@whbh int,
    as
    begin tran
    If not exists (select * from cgddmxb c where c.cgddh=@cgddh and c.key_id=@key_id and c.cbh=@cbh )
    begin
    Insert into cgddmxb(@cgddh,@key_id,@cbh,@sl,@dj)
    if exist (select * from ytfwh y where y.........)
    update ytfwh set...........
    else
    Insert into ytfwh(.....)
    end
    else
    update cgddmxb set(........)
    commit
    declare @1 date,@2 int,@3 int,@4 int,@5 int,
    declare xxx_cur cursor for
    select * from cgddmxb c inner join #cgddh g where c.cgddh=g.cgddh....
    for update
    open xxx_cur
    fetch next from xxx_cur into @1,@2,@3,@4,@5
    while @@fetch_status=0
    begin
    update ytfwh y
    set y.sl=y.sl-@4
    delete from cgddmxb where current of xxx_cur
    end
    close xxx_cur
    deallocate xxx_cur
    go
    不过有个问题,cgddmxb中没有whbh,它如何跟ytfwh对应起来呢?(对应你说的第3条).
      

  11.   

    cgddmxb是没有 whbh这个字段的,这个字段是 用户在combobox仓库条目选择的whbh仓库编号, 读出来动态给传的。
      

  12.   

    如果按照你描述的方法来实现,基本思路是:
    1.修改前,将所有需要修改的数据插入#cgddmxb,#cgddmxb1;
    2.修改时,修改#cgddmxb的内容,同时标记哪些行被修改;
    3.修改后通过#cgddmxb的修改标志得到表#cgddmxb1中作了修改的行,
      将这些行的内容与cgddmxb对比。如果对比有异,则回滚。
      如果无异,则将#cgddmxb的内容更新到cgddmxb中去。
    4.更新到cgddmxb的时候,将对应的修改反映到ytfwh表。
    是我整理的这个意思吗?
      

  13.   

    还有一个问题,对应你所说的第三条:
    3.在程序里修改的时候,如果有增加、删除、修改 #cgddmxb的记录的时候就会触发相应的ondelete,oninsert这些事件,就表示修改过了。
    那么,是否每次触发这些事件时都需要更新cbddmxb表呢?
      

  14.   

    2.修改#cgddmxb的内容,同时标记哪些行被修改;
    可以不做标记,因为一张单据最大限度只能开100条记录。3。我建#cgddmxb1的作用是为了防止我在修改这部分单据的时候,其它用户修改了我正在修改的数据而设定的。
    也就是在保存的时候,
    把cgddmxb的内容过滤出来和#cgddmxb1的内容进行对比,如果没有修改。则将#cgddmxb的内容更新到cgddmxb中去。如果其它用户有修改过就把其它用户修改后的数据调到 #cgddmxb 表里。让正在操作的用户显示的是其它用户最后修改过的单据。可以吗?
      

  15.   

    我想只要触发这些事件就表示修改过。
    就更新cgddmxb, 因为我的单据最大只能开100条记录,
      

  16.   

    做不到!(我觉得)
    你不至于会每两秒钟就去对比一下#cgddmxb1与cgddmxb表,并且把#cgddmxb在前端操作窗口刷新吧?
    不过,可以这样弄:用户操作时,是不管#cgddmxb1与cgddmxb是否一致的,只有当提交修改时才去做这个控制。
      

  17.   

    你说的对。就是这个意思, 不管#cgddmxb1与cgddmxb是否一致的,只有当提交修改时才去做这个控制。但去做这个控制的前提是,保证在提交的那一刻,其它用户没有修改过。
    也就是在提交前 再次把cgddmxb的内容读出来, 去和#cgddmxb1 的内容作比较,如果不符,说明我在修改的过程中其它用户个改了。这个时候就不允许提交,而是把其它用户修改后的单据调出来供目前用户修改。
    有可能其它用户把这张单据给删了。 那我在程序控制取下一单。
      

  18.   

    to  Chiff(~o~) 你现在理解了吗? 真的非常感谢您热情的帮助。
      

  19.   

    另外我想补充一下,因为还有其它的单据都有这样的操作。都是主表->明细表 改仓库表。所以
    我想能不能给这个存储过程传递一个  
    明细表名, 'cgddmxb', 仓库编号'whbh', '#cgddmxb'名,还有
    一个单号标识 cddh(这个标识对于每个明细表都不同,如cgddmxb-->cddh,ctmxb(采退明细表)->'ctdh'), 其它的属性都相同。可以写成一个公用的模块吗?
      

  20.   

    --创建一个存储过程,每次修改结束的时候执行这个存储过程:create proc myproc1
    @whbh  char(100)                     --将whbh赋值给这个存储过程
    asbegin tran                           --定义一个事务-------------------------------------------------------------------------------
    if exists(                           --首先判断是否别人已修改了数据select 1 
    from  (select a.*                    --得到本人修改了的行,先不管本人插的新行。
           from #cgddmxb1 a 
                left join #cgddmxb b
           on a.cgddh = b.cgddh and 
              a.key_id = b.key_id and 
              a.cbh = b.cbh
           where b.key_id is null         --表示本人删除了
                 or a.sl <> b.sl          --本人修改了数量
                 or a.dj <> b.dj          --本人修改了单价
           ) as c         left join cgddmxb d
    on c.cgddh = d.cgddh and c.key_id = d.key_id and c.cbh = d.cbh
    where d.key_id is null               --表示提交的时候别人已将他删除了
          or c.sl <> d.sl                --别人已修改了数量
          or c.dj <> d.dj)               --别人已修改了单价
        begin
        rollback
        raiserror 20001 '你修改的数据别人已经修改过了。'
        return -1
        end
    ---------------------------------------------------------------------------
    delete cgddmxb                      --将本人删除的行删除cgddmxb
    from   (select a.*
            from #cgddmxb1 a left join #cgddmxb b
            on a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
            where b.key_id is null) as c
    where  cgddmxb.cgddh = c.cgddh and 
           cgddmxb.key_id = c.key_id and 
           cgddmxb.cbh = c.cbh
    ---------------------------------------------------------------------------
    --将本人插入的行插入cgddmxb,此节要根据你的实际情况作修改,否则会错
    insert into cgddmxb                
    select a.*                         
    from #cgddmxb a left join #cgddmxb1 b
    on a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
    where b.key_id is null
    ---------------------------------------------------------------------------
    update cgddmxb                     --将本人修改的行修改cgddmxb
    set    sl = c.sl,
           dj = c.dj
    from  (select a.*
           from #cgddmxb a,#cgddmxb1 b
           where a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
                 and (a.sl <> b.sl  or a.dj <> b.dj)) as c
    where cgddmxb.cgddh  = c.cgddh  and 
          cgddmxb.key_id = c.key_id and 
          cgddmxb.cbh    = c.cbh
    ----------------------------------------------------------------------------
    insert into ytfwh                  --将ytfwh没有的列插入
    select distinct whbh=@whbh,cbh=isnull(a.cbh,b.cbh),sl=0
    from #cgddmxb a full join #cgddmxb1 b
    on a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
    where a.sl is null or b.sl is null or a.sl <> b.sl
          and cast(@whbh as char(100))+cast(isnull(a.cbh,b.cbh) as char(100))
              not in (select cast(whbh as char(100))+cast(cbh as char(100))
                      from ytfwh)
    ----------------------------------------------------------------------------
    update ytfwh                      --将ytfwh的sl更新
    set sl = c.sl
    from  (select whbh=@whbh,
                  cbh =isnull(a.cbh,b.cbh),
                  sl=sum( isnull(a.sl,0) - isnull(b.sl,0) )
           from #cgddmxb a full join #cgddmxb1 b
           on a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
           where a.sl is null or b.sl is null or a.sl <> b.sl
           group by isnull(a.cbh,b.cbh)  ) as c
    where ytfwh.whbh = c.whbh and ytfwh.cbh = c.cbh
    -----------------------------------------------------------------------------
    commit                          --提交。头也晕晕的了。不过我是一路测下来的。go
    如果你打算做成一个共用模板的话,就得用到动态语句。如下格式:
    create proc myproc1
    @whbh  char(100),                    --将whbh赋值给这个存储过程
    @表名   char(100),
    @动态语句 varchar(2000)
    as
    set @动态语句 = 'select * from '+@表名
    exec(@动态语句)
    ......
    这样做的结果会导致效率很低,不如多创建几个存储过程。或者按如下方式也可供参考,这样就只要创建一个存储过程:
    create proc myproc1
    @whbh  char(100),                    --将whbh赋值给这个存储过程
    @单据类型   int
    as
    if @单据类型 = 1
      begin
      --将那大段语句写进去
      end
    if @单据类型 = 2
      begin
      --将另一种单据的处理写进去
      end
    ......
      

  21.   

    你的写法效率很高,虽然我有些地方看得不太明白, 
    --首先判断是否别人已修改了数据
    这段过程,和我以前写的真的太好了。 以前我用delphi程序写出来,就是在程序里一行一行的判断。极慢。 我把#cgddmxb所有的数据都去和cgddmxb对比。而你现在 改成只在修改的才去对比。 减少了没有修改的行也去对比。
    算法很高。 我刚才在程序里测试这段程序。(出现个小问题,我通过图表建立了外键约束, 也就是cgddmxb表和cgdd主表通过cgdh建立了约束关系,如果在cgdd表里没有这个单号在cgddmxb中就不能插入这个单号。
    我每次测试都必须先到cgdd表里建一个单号。很麻烦。 
    (我建这个约束键的作用是。 如果要删除cgdd表的时候,明细表有记录就不能删除cgdd的这个单号), 你看能不能改为 可以在明细表里插入随便一个单号, 但在cgdd删除的时候如果这个单号已经在明细表里存在,就不能删除。
      

  22.   

    @动态语句 varchar(2000)
    as
    set @动态语句 = 'select * from '+@表名
    exec(@动态语句)
    ......
    这样做的结果会导致效率很低,不如多创建几个存储过程。为什么这样做效率很低。
    如果每个模块都写成一个单独的存储过程当然是好。但会很多重复的代码?
      

  23.   

    ----------------------------------------------------------------------------
    insert into ytfwh                  --将ytfwh没有的列插入
    select distinct whbh=@whbh,cbh=isnull(a.cbh,b.cbh),sl=0
    from #cgddmxb a full join #cgddmxb1 b //这里不太理解full join
    on a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
    where a.sl is null or b.sl is null or a.sl <> b.sl
          and cast(@whbh as char(100))+cast(isnull(a.cbh,b.cbh) as char(100))  //这里不太理解 cast的作用。
              not in (select cast(whbh as char(100))+cast(cbh as char(100))
                      from ytfwh)
    ----------------------------------------------------------------------------
    update ytfwh                      --将ytfwh的sl更新
    set sl = c.sl
    from  (select whbh=@whbh,
                  cbh =isnull(a.cbh,b.cbh),
                  sl=sum( isnull(a.sl,0) - isnull(b.sl,0) )
           from #cgddmxb a full join #cgddmxb1 b
           on a.cgddh = b.cgddh and a.key_id = b.key_id and a.cbh = b.cbh
           where a.sl is null or b.sl is null or a.sl <> b.sl
           group by isnull(a.cbh,b.cbh)  ) as c
    where ytfwh.whbh = c.whbh and ytfwh.cbh = c.cbh
    ----------------------------------------------------------------------------- a left join b 代表,在a中有在b中没有对不。
     b left join a 代表, 在b中有但在a中没有
     a full join b 是什么意思?
     cast起什么作用.
    大侠我给你发了短消息,有我没有考虑到的问题.
      

  24.   

    一、关于约束
    我相信你的cgdd表与cgddmxb中,cgdh的数目是一致的。即,只要某个cgdh在甲表中有,那么这个cgdh在乙表中也有。反之亦然。所以,我认为较好的做法是:在往明细表里面插入某个cgdh的同时,也向cgdd表插入这个cgdh信息。当明细表还有这个cgdh,就不允许删除主表的cgdh。二、动态语句
    其实,这个重复代码对于你来说,只是一个复制和简单修改,并不会增加你的工作量。他占用的资源是可以忽略的。而用动态语句有以下缺点:
      1、存储过程在第一次执行时进行编译,而以后调用就不用编译了。
       但如果是动态语句,则每次都要编译。而且你的动态语句还特别长!
      2、分多几个存储过程来写,比动态语句来说更透明化,便于你来调试。
        3、用动态语句来写,对你今后捕捉错误信息以及参数调出调入、临时表
       的修改创建都会带来不便.
        4、动态语句的好处就是调用的时候较简单,但是在存储过程中用if语句
       也来达到这个目的。
    三、我提供的只是一种思路和算法,你要根据你自已的实际情况作修改。
      

  25.   

    Chiff(~o~) 说得很详细很正确,听他的就好了。
    :)
      

  26.   

    full join 就是只要两个表中有一个有就OK
    cast是将数据转换的作用。比方说,我要找A、B两个表都有 L1(int)和L2(int)列,我要找出B表存在于A表的记录,可以:
    select * from a,b where a.l1 = b.l1 and a.l2 = b.l2但是,某些情况并不方便这样写语句,就可以通过这种方法:
    select * from a
    where cast(L1 as char(10))+cast(L2 as char(10))
         in (select cast(L1 as char(10))+cast(L2 as char(10)) from B)
      

  27.   

    非常感谢 Chiff(~o~) 热情的帮助, 大部分问题都得到解决。
    你说的对,不要把所有的控制都放在存储过程来做。 有些可以放到前台来做。 我也是这么想的。开始做的时候, 我的思路是想做成动态语句,如果从效率来讲我还是挺喜欢你说的那种方法, 不用动态语句。 就是简单的复制。  
    昨天晚上我很难理解的把这面的这段程序测试了一遍,哈哈,为什么说很难呢? 是因为我是个新手,对存储过和以及SQL不是很熟。在测试的时候我遇到几个问题, 对于left join, full join 这些我都理解了。 有几个问题还没弄明白。--将ytfwh没有的列插入里面
        
    我加了一个()
    where (a.sl is null or b.sl is null or a.sl <> b.sl)//如果没有加第二次运行就会报错, 加了更安全一些。
          and cast(@whbh as char(100))+cast(isnull(a.cbh,b.cbh) as char(100))
              not in (select cast(whbh as char(100))+cast(cbh as char(100))2.update ytfwh                      --将ytfwh的sl更新
    set sl = c.sl //这里我改成了set sl=ytfwh.sl+c.sl //如果不这么写 就会把原来已经的值全都替换掉了。
    from  (select whbh=@whbh,其它的都正确。另外raiserror 20001 '你修改的数据别人已经修改过了。' 这个错误我不知道怎样在查询分析器里能显示出来。如果出错,在前台会提示这个错误吗?
                      from ytfwh)