触发器里如何做到给用户提示错误信息后继续执行完成事务,急!

lcsdf 2007-01-16 04:24:46
各位大侠:
我用的是sql server2000,在金蝶K/3的采购订单表里写了一个触发器,想对单价超过最高限价的物资给操作者一个提示信息,但希望单据还可以保存。先是用了PRINT(),发现客户端不会出现提示消息框,然后采用了现在的RAISERROR(),可以出现提示框了,但是确认对话框后,单据无法保存。试过降低错误级别,10以下虽然可以保存单据,但不出现提示消息框,高于10的出现提示消息框,但点确定后无法保存单据,好像是事务被终止了,RAISERROR()后的语句也不再执行。有没有个两全齐美的办法,能够有提示消息框还能保存单据呀???不一定非得用RAISERROR(),有别的办法能实现也行!先谢谢大家了!!!我写的触发器的内容如下:
CREATE TRIGGER max_price ON dbo.POOrderEntry
FOR INSERT, UPDATE
AS
DECLARE
@price money,
@HighPrice money,
@itemid int,
@number varchar(80),
@name varchar(80),
@mess varchar(200)
select @price=Fprice,@itemid=Fitemid from INSERTED
select @highprice=FPOHighPrice from t_supply where fitemid=@itemid
if @price>@highprice or @highprice is null
BEGIN
select @number=Fnumber,@name=Fname from t_item where fitemid=@itemid and fitemclassid=4
select @mess=@number+' '+@name+' 单价超过最高限价!'
RAISERROR (@mess, 18, 18) //关键在这儿,能显示提示就不能保存单据
END
...全文
1375 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
netcup 2008-11-20
  • 打赏
  • 举报
回复

CREATE procedure SOF_dj_field_verify
@ask_interface integer=null, --该参数用来指示当前调用是否为接口询问(null:调用)
@djlxbs char(4)=null, --单据类型标识
@fieldname varchar(20)=null, --校验字段
@spid char(11)=null,
@spmch varchar(80)=null,
@shl dec(14,2)=null,
@chbdj dec(14,2)=null,
@dj dec(14,2)=null,
@hshj dec(14,2)=null,
@shlv dec(7,2)=null,
@xgdjbh char(11)=null,
@hw char(11)=null,
@pihao char(10)=null,
@jlgg int=null
as
/*******************************************************************************
***
为单据明细字段提供校验:返回列表,校验内容:

说明:1、该过程提供对单据明细字段的复杂校验,以根据实际需要来建立不同的校验模块,
2、每一校验模块的定位依赖于单据类型标识以及相关校验字段
3、校验模块的结构包括调用方法应答以及具体校验过程两部分
4、调用方法应答用来明确校验调用规范以及参数
5、校验执行结果信息返回结构为:[] as caption,[] as spmch,[] as holdup
6、holdup取值:0:提示不做拦截;>0提示并拦截;-1校验通过提示成功信息;<-1校
验通过隐含提示信息
7、校验模块框架:

--校验模块说明:
if (@djlxbs in ([单据类型1],[单据类型2],[,单据类型...])) and (@fieldname
=[校验字段名称])
begin
if @ask_interface is null
begin
--校验模块变量申明
declare @[变量]
if 满足条件
begin
--执行校验
end
else
begin
--校验通过
set @okmessage='校验成功提示信息'
set @holdup=-1 或 -2
goto ok_lab
end
end
else
begin
--返回调用方法
select [模块调用方法:如 exec SOF_dj_field_verify @djlxbs=:djlxbs,@fieldnam
e=:fieldname,@spbh=:spbh ' as proc_interface]
end
return 0 --跳出校验
end
8、校验模块注释必须增加
9、校验模块需要的参数在过程的参数列表中申明
10、校验模块中使用的变量必须申明在校验模块内部
********************************************************************************
***/
--定义参数
declare @okmessage varchar(255),
@holdup integer
set @holdup=-2

--采购入库单数量与开票数量进行校验
if (@djlxbs in ('120','','')) and (@fieldname='shl')
begin
declare @kpshl decimal(14,2)
if @ask_interface is null
begin
--执行校验
select @kpshl=sum(shl) from jxdjmx where djbh=@xgdjbh and spid=@spid
if @shl-@kpshl>0 --出库数量与开票数量之差大于0 时提示拦截,否则允许通过;
begin
select '入库数量不能大于开票数量,开票数量为:' as caption,convert(char(20),@kpshl),1 as holdup
end
else
goto ok_lab
end
else
begin
--返回调用方法
select 'exec SOF_dj_field_verify @djlxbs=:djlxbs,@fieldname=:fieldname,@spid
=:spid,@shl=:shl,@xgdjbh=:xgdjbh ' as proc_interface
end
return 0
end

--销售数量校验(到批次)
if (@djlxbs in ('212','','')) and (@fieldname='shl')
begin
declare @hwshl decimal(16,2)
declare @kpshl1 decimal(14,2)
declare @wckshl decimal(16,2)
declare @hjshl decimal(16,2)
declare @pcshl decimal(16,2)
declare @huowei char(20)

if @ask_interface is null
begin
set @hwshl=0
set @kpshl1=0
set @wckshl=0
set @hjshl=0
set @pcshl=0 --执行校验
select @pcshl=shl from sphwph(nolock) where spid=@spid and pihao=@pihao and hw=@hw
select @hwshl=shl from sphwph where spid=@spid and hw=@hw and pihao=@pihao
select @wckshl=sum(shl) from jxdjmxls where spid=@spid and hw=@hw and pihao=@pihao
select @huowei=huowname from huoweizl where hw=@hw
select @kpshl1=sum(shl) from tmp_dj_XSG212 where spid=@spid and hw=@hw and pihao=@pihao
select @jlgg=jlgg from spkfk where spid=@spid
set @hjshl=@hwshl-(isnull(@wckshl,0)+isnull(@kpshl1,0))
if ((@huowei='储备库') and (convert(int,@shl)%@jlgg<>0))
begin select '当前开票数量不是装量的倍数请注意' as caption,convert(char(20),@huowei),1 as holdup
end
else
if @hjshl-@shl<0 --开票数量与货位库存数量和开票未出库数量,正在开票数量之间进行校验提示拦截,否则允许通过;
begin
select '当前开票数量大于可销数量,可销数量为' as caption,convert(char(20),@hjshl),1 as holdup
end
else
goto ok_lab
end
else
begin
--返回调用方法
select 'exec SOF_dj_field_verify @djlxbs=:djlxbs,@fieldname=:fieldname,@spid
=:spid,@hw=:hw,@shl=:shl,@pihao=:pihao,@jlgg=:jlgg' as proc_interface
end
return 0
end
--出库价格低于最低售价校验

if (@djlxbs in ('212','','')) and (@fieldname='hshj')
begin
declare @zdsj dec(16,2)
if @ask_interface is null
begin
select @zdsj=zhdcbj from spkfk where spid=@spid
--执行校验
if @zdsj-@hshj>0 --最低售价限制大于含税价时提示拦截,否则允许通过;
begin
select '当前售价不允许小于最低售价,最低售价为' as caption,convert(char(20),@zdsj),1 as holdup
end
else
goto ok_lab
end
else
begin
--返回调用方法
select 'exec SOF_dj_field_verify @djlxbs=:djlxbs,@fieldname=:fieldname,@spid
=:spid,@hshj=:hshj ' as proc_interface
end
return 0
end
--内部调拨负库存拦截(字段校验)
if (@djlxbs in ('310','314','')) and (@fieldname='shl')
begin
declare @xswcshl decimal(16,2)
declare @xslskpshl decimal(16,2)
declare @dchwshl decimal(16,2)
declare @dkpshl decimal(14,2)
declare @dwckshl decimal(16,2)
declare @dhjshl decimal(16,2)

if @ask_interface is null
begin
set @dchwshl=0
set @dkpshl=0
set @dwckshl=0
set @dhjshl=0
--执行校验
select @xswcshl=sum(shl) from jxdjmx where is_zx='否' and is_zx<>'清'and spid=@spid and hw=@hw and pihao=@pihao and djbh like 'XSG%'
select @xslskpshl=sum(shl) from tmp_dj_XSG212 where spid=@spid and hw=@hw and pihao=@pihao
select @dchwshl=shl from sphwph where spid=@spid and hw=@hw and pihao=@pihao
select @dwckshl=sum(shl) from dbckmx where is_zx='否' and spid=@spid and dchw=@hw and pihao=@pihao AND DJBH LIKE 'KDB%'
if @djlxbs='310'
begin
select @dkpshl=sum(shl) from tmp_dj_KDB310 where spid=@spid and dchw=@hw and pihao=@pihao
end
if @djlxbs='314'
begin
select @dkpshl=sum(shl) from tmp_dj_cdb314 where spid=@spid and dchw=@hw and pihao=@pihao

set @dhjshl=@dchwshl-(isnull(@dwckshl,0)+isnull(@dkpshl,0)+isnull(@xslskpshl,0)+isnull(@xswcshl,0))

if ( (convert(int,@dhjshl)%@jlgg<>0))
begin select '当前开票数量不是装量的倍数请注意' as caption,convert(char(20),@dhjshl),1 as holdup
end

if @dhjshl-@shl<0 --开票数量与货位库存数量和开票未出库数量,正在开票数量之间进行校验提示拦截,否则允许通过;
begin
select '当前开票数量大于可销数量,可销数量为' as caption,convert(char(20),@dhjshl),1as holdup
end
else
goto ok_lab
end

end
else
begin
--返回调用方法
select 'exec SOF_dj_field_verify @djlxbs=:djlxbs,@fieldname=:fieldname,@spid
=:spid,@hw=:dchw,@shl=:shl,@pihao=:pihao' as proc_interface
end
return 0
end
--外调出库负库存拦截
if (@djlxbs in ('424','425','')) and (@fieldname='diaocsl')
begin
declare @wdcshl decimal(16,2)
declare @wdkpshl decimal(14,2)
declare @wdwckshl decimal(16,2)
declare @wdhjshl decimal(16,2)
if @ask_interface is null
begin
set @wdcshl=0
set @wdkpshl=0
set @wdwckshl=0
set @wdhjshl=0
--执行校验
select @wdcshl=shl from sphwph where spid=@spid and hw=@hw and pihao=@pihao

select @wdwckshl=sum(diaocsl) from dbkpcrkmx where is_zx='否' and spid=@spid
and hw=@hw and pihao=@pihao AND DJBH LIKE 'CKD%'
if @djlxbs='424'
begin
select @wdkpshl=sum(diaocsl) from tmp_dj_ckd424 where spid=@spid and
hw=@hw and pihao=@pihao
end
else
select @wdkpshl=sum(diaocsl) from tmp_dj_cck425 where spid=@spid and hw=
@hw and pihao=@pihao

set @wdhjshl=@wdcshl-(isnull(@wdwckshl,0)+isnull(@wdkpshl,0))

if @wdhjshl-@shl<0 --开票数量与货位库存数量和开票未出库数量,正在开票数量之间进行校验提示拦截,否则允许通过;
begin
select '当前开票数量大于可销数量,可销数量为' as caption,convert(char
(20),@wdhjshl), 1 as holdup
end
else
goto ok_lab
end
else
begin
--返回调用方法
select 'exec SOF_dj_field_verify @djlxbs=:djlxbs,@fieldname=:fieldname,@spid
=:spid,@hw=:hw,@shl=:diaocsl,@pihao=:pihao' as proc_interface
end
return 0
end

netcup 2008-11-20
  • 打赏
  • 举报
回复
给你个我们的程序的返回错误校验信息的存储过程!!
rucypli 2008-11-20
  • 打赏
  • 举报
回复
SET XACT_ABORT on
netcup 2008-11-20
  • 打赏
  • 举报
回复
这个一般是在应用程序里控制用户返回消息的。但是程序里一般都是获取存储过程的返回值给用户提示的。触发器的返回消息确实还不多。
vigor321 2008-11-20
  • 打赏
  • 举报
回复
呀,去年就懂了,我今年还不懂矣,试试用触发器与存储过程结合一下,看能否输出提示信息,但可以继续保存。我也用的金蝶K3,我也试过了好多方法,直到现在还没成功,我觉得可能用SQL2000是不行的,只能用编程的方法吧?
wudan8057 2007-01-17
  • 打赏
  • 举报
回复
既然原来就有的就不要删除了,肯定对数据产生影响.
看看在POOrderEntry 上有没有定义约束.
achongsky 2007-01-17
  • 打赏
  • 举报
回复
CREATE TRIGGER AuxQty_POOrder ON [POOrderEntry]
FOR INSERT,Update
AS
Update t1 set t1.FQty=t2.FAuxQty*(isnull(t3.FCoefficient,1)+isnull(t3.FScale,0)),t1.FPrice=t2.FAuxPrice/(isnull(t3.FCoefficient,1)+isnull(t3.FScale,0))
from POOrderEntry t1,Inserted t2,t_MeasureUnit t3
where t1.FInterID=t2.FInterID and t1.FEntryID=t2.FEntryID and t3.FItemID=t2.FUnitID

--------------
像类似这样的触发器会循环触发进入死循环吗?因为触发器里又update同样的表了,是不是又会再触发触发器呢?
做了下测试应该不会死循环,有人能说说这是SQL的什么机制吗?
lcsdf 2007-01-17
  • 打赏
  • 举报
回复
回wudan8057(上善若水),再次感谢你呀!!!我又试验了一下,发现是因为我的那个表(poorderentry)还有一个触发器,也是在insert,update的时候触发,当我把它删除后,就可以即能提示,又能保存数据了。但是它是金蝶自己的触发器,我怕直接这么删掉会有影响。原来的触发器是这样的:
CREATE TRIGGER AuxQty_POOrder ON [POOrderEntry]
FOR INSERT,Update
AS
Update t1 set t1.FQty=t2.FAuxQty*(isnull(t3.FCoefficient,1)+isnull(t3.FScale,0)),t1.FPrice=t2.FAuxPrice/(isnull(t3.FCoefficient,1)+isnull(t3.FScale,0))
from POOrderEntry t1,Inserted t2,t_MeasureUnit t3
where t1.FInterID=t2.FInterID and t1.FEntryID=t2.FEntryID and t3.FItemID=t2.FUnitID

我现在怎么做比较好呀?直接在这个触发器里加上我的那段?
wudan8057 2007-01-17
  • 打赏
  • 举报
回复
在这个表上是不是还有别的触发器?
wudan8057 2007-01-17
  • 打赏
  • 举报
回复
--做了一个测试,没有出现你说的这种情况
USE pubs
GO

CREATE TABLE test(id INT)
GO

CREATE trigger t_inserttest on test
for insert
as
begin
declare @i_number INT
SELECT @i_number = count(*) from inserted
update num set number = number + isnull(@i_number,0) --更新插入的记录数
raiserror('this is test',18,18)
end
GO

CREATE TABLE num(number INT)
GO

INSERT num VALUES(0)
GO

SELECT * FROM num --执行前
INSERT test VALUES(1)
SELECT * FROM num --执行后
SELECT * FROM test

DROP TABLE test
DROP TABLE num
lcsdf 2007-01-17
  • 打赏
  • 举报
回复
回wudan8057(上善若水),首先非常感谢你的热心回复,我按你说的方法在查询分析器里试过了,只要是提示错误信息,所做的改动就不能保存。
wudan8057 2007-01-17
  • 打赏
  • 举报
回复
发现能保存单据,但是客户端不弹出错误提示窗口了,在查询分析器里是可以看到提示错误信息的。

--
既然在查询分析中可以看到,怀疑是金蝶的软件做了控制.将RAISERROR (@mess, 18, 18)改一下看什么结果,如果还不行的,那就没有什么办法了!
改为:RAISERROR (@mess, 16, 1)
lcsdf 2007-01-17
  • 打赏
  • 举报
回复
回wudan8057(上善若水),真是非常感谢你如此热心的回复,我按你写的试了一下,发现能保存单据,但是客户端不弹出错误提示窗口了,在查询分析器里是可以看到提示错误信息的。两个触发器都存在的话就可以从客户端弹出窗口,但不能保存。只保留我写的那个触发器也能保存单据,但是同样没错误提示窗口。真是奇怪了,难道真的没有两全的办法吗?
wudan8057 2007-01-17
  • 打赏
  • 举报
回复
--试一试,将两个触发器合并:
CREATE TRIGGER AuxQty_POOrder ON [POOrderEntry]
FOR INSERT,Update
AS
@price money,
@HighPrice money,
@itemid int,
@number varchar(80),
@name varchar(80),
@mess varchar(200)

Update t1 set t1.FQty=t2.FAuxQty*(isnull(t3.FCoefficient,1)+isnull(t3.FScale,0)),t1.FPrice=t2.FAuxPrice/(isnull(t3.FCoefficient,1)+isnull(t3.FScale,0))
from POOrderEntry t1,Inserted t2,t_MeasureUnit t3
where t1.FInterID=t2.FInterID and t1.FEntryID=t2.FEntryID and t3.FItemID=t2.FUnitID

IF @@Error = 0 --更新成功提示用户,不成功不用提示
BEGIN
select @price=Fprice,@itemid=Fitemid from INSERTED
select @highprice=FPOHighPrice from t_supply where fitemid=@itemid
if @price>@highprice or @highprice is null
BEGIN
select @number=Fnumber,@name=Fname from t_item where fitemid=@itemid and fitemclassid=4
select @mess=@number+' '+@name+' 单价超过最高限价!'
RAISERROR (@mess, 18, 18) //关键在这儿,能显示提示就不能保存单据
END
END
lcsdf 2007-01-17
  • 打赏
  • 举报
回复
刚看了一下,除了主键外,没什么约束了。我该怎么办?
wudan8057 2007-01-16
  • 打赏
  • 举报
回复
SQL SERVER2000的触发器在执行时如果发生任何错误,需要用户调用rollback tran回滚事物,否则后面的语句仍然会执行.也就是事物仍然会提交.上面的语句肯定是没有问题的.应该是应用程序中做了回滚操作.
可以试一试在查询分析器中执行一条语句来激活上面的触发器.看看是否满足你的要求.

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧