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条).
--创建一个存储过程,每次修改结束的时候执行这个存储过程: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 ......
@动态语句 varchar(2000) as set @动态语句 = 'select * from '+@表名 exec(@动态语句) ...... 这样做的结果会导致效率很低,不如多创建几个存储过程。为什么这样做效率很低。 如果每个模块都写成一个单独的存储过程当然是好。但会很多重复的代码?
---------------------------------------------------------------------------- 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起什么作用. 大侠我给你发了短消息,有我没有考虑到的问题.
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)
我加了一个() 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)
whbh+cbh对应的ytfwh表里的whbh+cbh的这条记录sl的 值 减去cgddmxb中的
这条记录的sl的值) cgddmxb表中没有whbh啊?你好好读读你的问题,确认没有逻辑错误再发上来
字段内容为
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。
在程序通过:whbh传给存储过程可以吧
cgddmxb
cddh,cbh, key_idcgthmxb
ctdh, cbh, key_id
所以存储过程只要给存储过程传表名 cgddmxb/cgthmxb, cddh/ctdh/, whbh
三个参数。
不知道我的想法有没有问题。请您指点。
我想因为很多模块都涉及到对 ytfwh仓库表的sl进增加、修改。 但不删除这个表的数据。是不能删除ytfwh表的数据
一、你为什么要将cgddmxb的数据调到#cgddmxb修改?
二、你修改的时候是将所有的数据导到#cgddmxb,还是有条件的导?
三、修改完后,你凭什么来判断数据已修改?是将#cgddmxb与cgddmxb对比,还是根据#cgddmxb本身的变化?(而临时表是不能建触发器的!)如果将#cgddmxb与cgddmxb两表对比,万一在修改的时候别人也修改了怎么办?将他的修改改回去???
总之我觉得你的设计不是很合理。若可以,你把你的设计来龙去脉的表达出来,发消息给我也可以,我再帮你参考一下。不过今天不行了。
Chiff(~o~) 说得太对了,这种做法问题多多。整个处理思路要重新整理一下。
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的内容作对比,只要有一个字段的内容不相同, 就表示。在我修改的过程中有其它用户修改过, 回滚事务。
key_id从1..100
@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条).
1.修改前,将所有需要修改的数据插入#cgddmxb,#cgddmxb1;
2.修改时,修改#cgddmxb的内容,同时标记哪些行被修改;
3.修改后通过#cgddmxb的修改标志得到表#cgddmxb1中作了修改的行,
将这些行的内容与cgddmxb对比。如果对比有异,则回滚。
如果无异,则将#cgddmxb的内容更新到cgddmxb中去。
4.更新到cgddmxb的时候,将对应的修改反映到ytfwh表。
是我整理的这个意思吗?
3.在程序里修改的时候,如果有增加、删除、修改 #cgddmxb的记录的时候就会触发相应的ondelete,oninsert这些事件,就表示修改过了。
那么,是否每次触发这些事件时都需要更新cbddmxb表呢?
可以不做标记,因为一张单据最大限度只能开100条记录。3。我建#cgddmxb1的作用是为了防止我在修改这部分单据的时候,其它用户修改了我正在修改的数据而设定的。
也就是在保存的时候,
把cgddmxb的内容过滤出来和#cgddmxb1的内容进行对比,如果没有修改。则将#cgddmxb的内容更新到cgddmxb中去。如果其它用户有修改过就把其它用户修改后的数据调到 #cgddmxb 表里。让正在操作的用户显示的是其它用户最后修改过的单据。可以吗?
就更新cgddmxb, 因为我的单据最大只能开100条记录,
你不至于会每两秒钟就去对比一下#cgddmxb1与cgddmxb表,并且把#cgddmxb在前端操作窗口刷新吧?
不过,可以这样弄:用户操作时,是不管#cgddmxb1与cgddmxb是否一致的,只有当提交修改时才去做这个控制。
也就是在提交前 再次把cgddmxb的内容读出来, 去和#cgddmxb1 的内容作比较,如果不符,说明我在修改的过程中其它用户个改了。这个时候就不允许提交,而是把其它用户修改后的单据调出来供目前用户修改。
有可能其它用户把这张单据给删了。 那我在程序控制取下一单。
我想能不能给这个存储过程传递一个
明细表名, 'cgddmxb', 仓库编号'whbh', '#cgddmxb'名,还有
一个单号标识 cddh(这个标识对于每个明细表都不同,如cgddmxb-->cddh,ctmxb(采退明细表)->'ctdh'), 其它的属性都相同。可以写成一个公用的模块吗?
@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
......
--首先判断是否别人已修改了数据
这段过程,和我以前写的真的太好了。 以前我用delphi程序写出来,就是在程序里一行一行的判断。极慢。 我把#cgddmxb所有的数据都去和cgddmxb对比。而你现在 改成只在修改的才去对比。 减少了没有修改的行也去对比。
算法很高。 我刚才在程序里测试这段程序。(出现个小问题,我通过图表建立了外键约束, 也就是cgddmxb表和cgdd主表通过cgdh建立了约束关系,如果在cgdd表里没有这个单号在cgddmxb中就不能插入这个单号。
我每次测试都必须先到cgdd表里建一个单号。很麻烦。
(我建这个约束键的作用是。 如果要删除cgdd表的时候,明细表有记录就不能删除cgdd的这个单号), 你看能不能改为 可以在明细表里插入随便一个单号, 但在cgdd删除的时候如果这个单号已经在明细表里存在,就不能删除。
as
set @动态语句 = 'select * from '+@表名
exec(@动态语句)
......
这样做的结果会导致效率很低,不如多创建几个存储过程。为什么这样做效率很低。
如果每个模块都写成一个单独的存储过程当然是好。但会很多重复的代码?
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起什么作用.
大侠我给你发了短消息,有我没有考虑到的问题.
我相信你的cgdd表与cgddmxb中,cgdh的数目是一致的。即,只要某个cgdh在甲表中有,那么这个cgdh在乙表中也有。反之亦然。所以,我认为较好的做法是:在往明细表里面插入某个cgdh的同时,也向cgdd表插入这个cgdh信息。当明细表还有这个cgdh,就不允许删除主表的cgdh。二、动态语句
其实,这个重复代码对于你来说,只是一个复制和简单修改,并不会增加你的工作量。他占用的资源是可以忽略的。而用动态语句有以下缺点:
1、存储过程在第一次执行时进行编译,而以后调用就不用编译了。
但如果是动态语句,则每次都要编译。而且你的动态语句还特别长!
2、分多几个存储过程来写,比动态语句来说更透明化,便于你来调试。
3、用动态语句来写,对你今后捕捉错误信息以及参数调出调入、临时表
的修改创建都会带来不便.
4、动态语句的好处就是调用的时候较简单,但是在存储过程中用if语句
也来达到这个目的。
三、我提供的只是一种思路和算法,你要根据你自已的实际情况作修改。
:)
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)
你说的对,不要把所有的控制都放在存储过程来做。 有些可以放到前台来做。 我也是这么想的。开始做的时候, 我的思路是想做成动态语句,如果从效率来讲我还是挺喜欢你说的那种方法, 不用动态语句。 就是简单的复制。
昨天晚上我很难理解的把这面的这段程序测试了一遍,哈哈,为什么说很难呢? 是因为我是个新手,对存储过和以及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)