请帮解决两个(也是4个)问题,每个100分,谢谢!

人生无悔 2012-07-22 09:17:28

------------------------
/******
建表
******/
------------------------
if object_id('p') is not null
drop table p
go
create table p(
name nvarchar(20) not null,
ver nvarchar(20) not null,
active bit null,
constraint [pk_p] primary key(name,ver)
)
go
------------------------
/******
建触发器
******/
------------------------
create trigger p_upd
on p
for update
as
if update(active) and (select count(1) from inserted)>1
begin
rollback tran;
raiserror('每次只能更新一条',11,1);
return;
end
if update(active)
begin
update p set active=0
from inserted i
where i.name=p.name and i.ver<>p.ver
and isnull(i.active,0)=1;
end
go
------------------------
/******
测试数据
******/
------------------------
insert into p values('p1','a',0);
insert into p values('p1','b',1);
insert into p values('p1','c',0);
go
------------------------

要求:
1.如何更新,让两条数据的active同时为1,并如何可避免这种问题发生???

2.如果去掉此句,让两条数据的active同时为1,并如何可避免这种问题发生???

前提:请不要禁用此触发器

if update(active) and (select count(1) from inserted)>1
begin
rollback tran;
raiserror('每次只能更新一条',11,1);
return;
end
...全文
146 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
筱筱澄 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

引用 1 楼 的回复:

SQL code
第一个问题



update p set name='p2',ver='f',active=1 where name='p1' and ver='c'
select * from p
--下面这样的算不算?
/*
name ver active
-------……
[/Quote]
我晕,有写错了,原理说对了,语句老是错。

看来真是喝多了。。。。。。。。。。。。。。
if update(active)
begin
update p set active=0
from inserted i
where i.name=p.name and i.ver=p.ver
;
end



第二个,我写的更新同样适合你。避免方法也适合

还有下面的更新也可以


update p set name='p2',active=1 where ver='c'
--or
update p set name='p3',active=1 where ver='a'



看来真是喝多了,好晕,睡觉觉

筱筱澄 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

SQL code
第一个问题



update p set name='p2',ver='f',active=1 where name='p1' and ver='c'
select * from p
--下面这样的算不算?
/*
name ver active
-------------------- -----------……
[/Quote]

错了,应该还得改一个条件
替换成下面的。有点晚了 脑子不好使了

  if update(active)
begin
update p set active=0
from inserted i
where i.name=p.name and i.ver=p.ver
and isnull(i.active,0)=1 ;
end
筱筱澄 2012-07-23
  • 打赏
  • 举报
回复
第一个问题



update p set name='p2',ver='f',active=1 where name='p1' and ver='c'
select * from p
--下面这样的算不算?
/*
name ver active
-------------------- -------------------- ------
p1 a 0
p1 b 1
p2 f 1

(3 行受影响)

*/
--如果对,要避免的话 把 and isnull(i.active,0)=1;
--去掉,因为一次只能更新一行,那么它跟定的把0的更新成1才会出现两行
--所以你只需要把更新的那一行在更新一遍(更新为0),就行了。
人生无悔 2012-07-23
  • 打赏
  • 举报
回复
並不是沒考慮新增,只是我沒寫在這裡,有二十幾個庫同時使用相同的腳本,其中兩個庫有問題

客戶端程序是不會union all同時新增幾倏的,而且新增時是不可以啟用的,啟用是單獨按鈕控制的,啟用了一次會有通知郵件的,並不是數據庫中隨便操作的

呵呵,沒法說得太多,不然就沒人看了,還是不浪費大家的時間了,看來是沒結果的,我還是結帖吧

非常感謝各位,謝謝大家參與
昵称被占用了 2012-07-23
  • 打赏
  • 举报
回复
第二个问题,用如下语句测试几次


UPDATE P SET active = 1
WHERE ver <> 'B'


insert into p SELECT 'p1','f',1
UNION ALL SELECT 'p1','G',1
昵称被占用了 2012-07-23
  • 打赏
  • 举报
回复
第二个问题,触发器如下修改即可


------------------------
/******
建触发器
******/
------------------------
ALTER trigger p_upd
on p
for update,INSERT
as
if update(active)
begin
update p set active=0
from inserted i
where i.name=p.name and i.ver<>p.ver
and isnull(i.active,0)=1
AND NOT EXISTS (
SELECT 1 FROM inserted i1
WHERE I1.NAME = I.NAME AND i1.ver>I.ver
)
end
go
SQL77 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]
引用 6 楼 的回复:
可能要求太多了,呵呵,就一个要求吧

模拟出来让两个active同时为一的情况就可以了,另外都不需要回答了,
其他另开帖解决,谢谢!

insert into p values('p1','D',1);
就会有两条1的了
[/Quote]
海爷说的是。。
昵称被占用了 2012-07-23
  • 打赏
  • 举报
回复
关键是你没有考虑插入情况,触发器如下修改

------------------------
/******
建触发器
******/
------------------------
ALTER trigger p_upd
on p
for update,INSERT
as
if update(active) and (select count(1) from inserted)>1
begin
rollback tran;
raiserror('每次只能更新一条',11,1);
return;
end
if update(active)
begin
update p set active=0
from inserted i
where i.name=p.name and i.ver<>p.ver
and isnull(i.active,0)=1;
end
go
昵称被占用了 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]
可能要求太多了,呵呵,就一个要求吧

模拟出来让两个active同时为一的情况就可以了,另外都不需要回答了,
其他另开帖解决,谢谢!
[/Quote]
insert into p values('p1','D',1);
就会有两条1的了
SQL77 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]
可能要求太多了,呵呵,就一个要求吧

模拟出来让两个active同时为一的情况就可以了,另外都不需要回答了,
其他另开帖解决,谢谢!
[/Quote]
我来写的话
INSTEAD OF 触发器:判断如果有更新。并且 select 1 from inserted i
where exists(select 1 from inserted where i.name=p.name and i.ver<>p.ver)
回滚:否则则更新。。

但这样回滚的话假如更新了P1,P2两个。可能P2只更新了一行也回滚了。
--小F-- 2012-07-23
  • 打赏
  • 举报
回复
1.有主键还能出现两个为1的情况吗?你的隔离级别是默认的吗?
如果是读已提交的话 有可能出问题

2.你的操作是对的啊 先判断一下
SQL77 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]
可能要求太多了,呵呵,就一个要求吧

模拟出来让两个active同时为一的情况就可以了,另外都不需要回答了,
其他另开帖解决,谢谢!
[/Quote]
DBCC USEROPTIONS
GO

给结果。
筱筱澄 2012-07-23
  • 打赏
  • 举报
回复
我靠。。。。。。。。这什么帖子吗?还以为会给我200
人生无悔 2012-07-23
  • 打赏
  • 举报
回复
可能要求太多了,呵呵,就一个要求吧

模拟出来让两个active同时为一的情况就可以了,另外都不需要回答了,
其他另开帖解决,谢谢!
SQL77 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
引用 1 楼 的回复:
SQL code
第一个问题



update p set name='p2',ver='f',active=1 where name='p1' and ver='c'
select * from p
--下面这样的算不算?
/*
name ver active
-------------------- ---……

不好意思,名称和版本号为主键……
[/Quote]
1。如果按你的情况。只能更改ACTIVE。如果有语句判断了。根本不可能出现两个为1的情况。
你的隔离级别是什么?
2。先判断再更新是正确的。
要不然先更新后再判断一次是否有两个=1的。这时个再来查看原因

----用跟踪器跟踪一下。

人生无悔 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]
SQL code
第一个问题



update p set name='p2',ver='f',active=1 where name='p1' and ver='c'
select * from p
--下面这样的算不算?
/*
name ver active
-------------------- ---……
[/Quote]
不好意思,名称和版本号为主键,客户端程序中是无法修改的,只可以修改是否启用active栏位

这是开发中实际遇到的问题,呵呵,我设计的bom,但是客户20多个数据库中有一个数据库是存在这种情况的,可能是并发造成的,但模拟几个客户端同时执行操作都没有产生两条为1的
谢谢!

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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