Sql 如何设置一条记录标记为1,其他所有记录标记为0
我有一个表地址,列ID为PK、EmpID为int、地址为nvarchar100、IsDefault位。 现在我必须确保只有一个具有相同EmpID的记录IsDefault设置为1。 我现在已经完成了触发器的跟踪。 第一个是插入触发器。首先,它检查IsDefault中是否输入了值1。如果是,则检查是否有多条记录的EmpID和IsDefault值设置为1。如果这也是真的,那么它会将同一EmpID的所有其他IsDefault值设置为0: 另一个是更新触发器,我不知道如何编写它。首先,它执行与插入触发器相同的操作,检查插入值是否为1,其中值为0。如果是,如果有多条记录具有相同的EmpID,并且IsDefault设置为1。如果是 如何写入将同一EmpID的所有其他记录设置为0,而正在更新的记录保持为1Sql 如何设置一条记录标记为1,其他所有记录标记为0,sql,sql-server,Sql,Sql Server,我有一个表地址,列ID为PK、EmpID为int、地址为nvarchar100、IsDefault位。 现在我必须确保只有一个具有相同EmpID的记录IsDefault设置为1。 我现在已经完成了触发器的跟踪。 第一个是插入触发器。首先,它检查IsDefault中是否输入了值1。如果是,则检查是否有多条记录的EmpID和IsDefault值设置为1。如果这也是真的,那么它会将同一EmpID的所有其他IsDefault值设置为0: 另一个是更新触发器,我不知道如何编写它。首先,它执行与插入触发器相
create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_update]
on [dbo].[Addresses]
after update
as
begin
set nocount on;
begin try
if exists (
select *
from inserted as i
inner join deleted as d on d.ID=i.ID
where i.IsDefault = 1
and d.IsDefault = 0)
begin
if (
select count(*)
from dbo.Addresses as lao
inner join inserted as i on i.ID=lao.ID
where lao.IsDefault = 1
and lao.EmpID = i.EmpID
) > 1
begin
update lao
set lao.IsDefault = 0
from dbo.Addresses as lao
inner join inserted as i on i.ID=lao.ID
where (I don't have an idea what to put here)
and lao.OrganisationID = i.OrganisationID
end
end
end try
begin catch
if @@trancount > 0
rollback tran;
end catch
end
我正在研究MS SQL 2016。< /P> < P>我可以考虑一下,如果没有触发器,你要解决的问题是否可以解决。触发器往往会带来显著的性能损失,并且会将逻辑与代码的其余部分分开,这使得在将来维护它成为一件令人头痛的事情
如果您真的想在行插入/更新时使用触发器解决方案,并且始终有一行用位标记,那么不要尝试使用它计算行数。只需将相关EmpID的所有行设置为0,然后在触发器中将插入的行更新为1。我同意Matt的观点:如果可能,避免触发 无论如何,我认为在更新触发器中,您应该更改为:
if (
select count(*)
from dbo.Addresses as lao
inner join inserted as i on lao.EmpID = i.EmpID
where lao.IsDefault = 1
) > 1
begin
update lao
set lao.IsDefault = 0
from dbo.Addresses as lao
inner join inserted as i on lao.EmpID = i.EmpID
where lao.IsDefault = 1
and lao.ID <> i.id
end
此外,您可以将其改写为:
IF EXISTS(SELECT 1 FROM
FROM dbo.Addresses as lao
INNER join inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1 AND lao.ID <>i.ID)
BEGIN
UPDATE lao
SET lao.IsDefault = 0
FROM dbo.Addresses as lao
INNER JOIN inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
and lao.ID <> i.id
END
您也应该更改插入触发器
更新:插入触发器。
就我所见,但我不能做测试,所以请做完整的案例测试,如果ID总是最大值,或者如果您想保留上次插入的ID的默认值,我想您可以如下重写您的插入触发器:您可以删除if-too,如果您不关心总是对零行进行更新的话
as
begin
set nocount on;
begin try
IF EXISTS(SELECT 1
FROM dbo.Addresses as lao
INNER join inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
AND lao.ID <>i.ID
AND i.IsDefault=1)
BEGIN
UPDATE lao
SET lao.IsDefault = 0
FROM dbo.Addresses as lao
INNER JOIN inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
and lao.ID <> i.id
AND i.IsDefault=1
END
end try
begin catch
if @@trancount > 0
rollback tran;
end catch
此更改和i.IsDefault=1也可应用于更新触发器。此处所需的行为是什么?是否有其他默认值像您当前实现的那样神奇地设置为0,或者每个empid最多可以将一行设置为1?如果是后者,并且产生错误而不是更改其他数据是可以接受的,则可以通过过滤索引来实现。@damien the Insiever:每个EmpID都有一条记录。我可以在一个表中有多个EmpID,但只有一个可以将IsDefault设置为1。所有其他值必须为0。可以更改同一EmpID的默认地址。所以我不能使用索引,因为我希望能够为相同的EmpID在其他地址上更改IsDefault值。所以你想神奇地更改其他行的行为吗?因为很明显,如果您先取消设置当前默认值,然后再设置新的defaultyes,索引工作正常。我希望它得到改变。如果有任何其他方式,然后触发,我在这里听。我在想,没有触发器是不可能做到这一点的。正如我对马特的回答:如果有任何其他方法,那么触发器,让我知道。我也不喜欢触发器,但是没有触发器我无法找到如何操作,因为我必须在更新时更改字段中的值。如果你能告诉我,我的插入触发器有什么问题?或者你的意思是,如果存在,最好将其重写为?我认为你应该删除I.ID=lao.ID上的insert触发器,并使用与我为UPDATE触发器编写的相同的值,然后你可以选择使用COUNT或exists,但我认为应该修改join子句。你插入的列ID总是更高的值?是的。ID列始终较高。这是一个身份1,1。
as
begin
set nocount on;
begin try
IF EXISTS(SELECT 1
FROM dbo.Addresses as lao
INNER join inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
AND lao.ID <>i.ID
AND i.IsDefault=1)
BEGIN
UPDATE lao
SET lao.IsDefault = 0
FROM dbo.Addresses as lao
INNER JOIN inserted as i on lao.EmpID = i.EmpID
WHERE lao.IsDefault = 1
and lao.ID <> i.id
AND i.IsDefault=1
END
end try
begin catch
if @@trancount > 0
rollback tran;
end catch