Sql server sql server中一组行的默认行1

Sql server sql server中一组行的默认行1,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,每当用户添加、更新和删除行时,每个公司的iPrimary都应该是唯一的。也就是说,对于每个CompanyID,应该只有一行IsPrimary=1 条件: 对于每个公司ID,只能有一行IsPrimary=1 对于每个公司ID,所有行不应为IsPrimary=0 如果用户删除IsPrimary行,则其他行应分配IsPrimary=1 当用户第一次输入记录时,用户将选择isprimary,即使他忘记了我们的查询也应分配isprimary=1' 5当输入第二条记录时,如果他分配isPrimary=1,如

每当用户添加、更新和删除行时,每个公司的iPrimary都应该是唯一的。也就是说,对于每个CompanyID,应该只有一行IsPrimary=1

条件:

对于每个公司ID,只能有一行IsPrimary=1 对于每个公司ID,所有行不应为IsPrimary=0 如果用户删除IsPrimary行,则其他行应分配IsPrimary=1 当用户第一次输入记录时,用户将选择isprimary,即使他忘记了我们的查询也应分配isprimary=1' 5当输入第二条记录时,如果他分配isPrimary=1,如果isPrimary存在于同一公司id中,则该记录应为isPrimary=0' 6.如果现有iPrimary将1更改为0,则应分配iPrimary=1的同一公司id下的其他前1名记录 我希望你了解我的情况

我也在msdn中提出了这个问题

有些人给出了近似的解决方案,但它在所有条件下都能工作

CREATE TABLE ContactInfo (
ID int IDENTITY(1,1) NOT NULL,
CompanyID int NOT NULL, 
ContactName varchar(45) DEFAULT NULL,
IsPrimary bit DEFAULT NULL
PRIMARY KEY (id)
)

INSERT INTO ContactInfo (CompanyID,ContactName,IsPrimary) VALUES (1,'Vijay',1);
INSERT INTO ContactInfo (CompanyID,ContactName,IsPrimary) VALUES (1,'Amit',0);

ID  CompanyID   ContactName IsPrimary
1   1           Vijay       1
2   1           Amit        0

提供的触发器部分执行此任务,但不允许您控制当您从组中删除最后一个IsPrimary标志或由于插入或升级而有多个IsPrimary标志时,如何处理IsPrimary标志的情况

为了简化测试,我对ContactInfo做了一点修改-iPrimary默认值为0,因为除了一条记录外,其他所有记录都有1:

CREATE TABLE ContactInfo (
ID int IDENTITY(1,1) NOT NULL,
CompanyID int NOT NULL, 
ContactName varchar(45) DEFAULT NULL,
IsPrimary bit DEFAULT NULL
PRIMARY KEY (id)
)
GO

CREATE TRIGGER trg1  ON ContactInfo  AFTER INSERT, UPDATE, DELETE
AS
    --UPDATE ContactInfo SET IsPrimary=1 FROM ContactInfo JOIN inserted I ON I.CompanyID=.ContactInfo.CompanyID
    --for INSERT 
    IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted)
       UPDATE T SET IsPrimary= CASE WHEN RN=1 THEN 1 ELSE 0 END
       FROM (SELECT ROW_NUMBER() OVER(PARTITION BY CompanyID ORDER BY (SELECT 1)) RN,IsPrimary 
       FROM ContactInfo WHERE CompanyID IN(SELECT CompanyID FROM inserted)) T

    --for UPDATE
    ELSE IF EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
       UPDATE T SET IsPrimary= CASE WHEN RN=1 THEN 1 ELSE 0 END
       FROM (SELECT ROW_NUMBER() OVER(PARTITION BY CompanyID ORDER BY (SELECT 1)) RN,IsPrimary 
       FROM ContactInfo WHERE CompanyID IN(SELECT CompanyID FROM inserted)) T

    --for DELETE
    ELSE
       UPDATE T SET IsPrimary= CASE WHEN RN=1 THEN 1 ELSE 0 END
       FROM (SELECT ROW_NUMBER() OVER(PARTITION BY CompanyID ORDER BY (SELECT 1)) RN,IsPrimary 
       FROM ContactInfo WHERE CompanyID IN(SELECT CompanyID FROM deleted)) T
GO 


--insert one row with is primary 0
INSERT INTO ContactInfo (CompanyID,ContactName,IsPrimary) VALUES (1,'Vijay',0);
--IsPrimary gets 1 actually
SELECT * FROM ContactInfo

--add one more row for the same company id 1 with IsPrimary=1
INSERT INTO ContactInfo (CompanyID,ContactName,IsPrimary) VALUES (1,'Amit',1);
--IsPrimary gets 0 actually
SELECT * FROM ContactInfo

--update the Isprimary to 1 for Amit
UPDATE ContactInfo SET IsPrimary=1 WHERE CompanyID=1 and ContactName='Amit'
SELECT * FROM ContactInfo

--delete Vijay whose IsPrimary=1
DELETE ContactInfo WHERE CompanyID=1 and ContactName='Vijay'
--Amit's Isprimary has been set 1
SELECT * FROM ContactInfo
现在,新的触发器:

基本上,我正在尝试处理以下情况:

组中没有主-添加到组中的一个 组中有多个主节点 如果primary来自inserted,请使用该选项 否则从实际表中使用

-- drop table ContactInfo
CREATE TABLE ContactInfo (
    ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
    CompanyID int NOT NULL, 
    ContactName varchar(45) DEFAULT NULL,
    IsPrimary bit NOT NULL DEFAULT(0)
)
GO
这是相当复杂的,所以我会尝试从应用程序中删除它,正如在一个答案中已经建议的那样

对于每个CompanyID,应该只有一行具有IsPrimary= 一,

若要强制执行此操作,请创建筛选的唯一索引。索引在IsPrimary=1时过滤,在CompanyID上是唯一的

大概是这样的:

truncate table ContactInfo
go

-- first records should be primary
INSERT INTO ContactInfo (CompanyID,ContactName) VALUES (1,'Some name 1'), (2, 'Some name 2')
SELECT 'first records', * FROM ContactInfo
GO

-- multiple insert - should not get primary
INSERT INTO ContactInfo (CompanyID,ContactName) VALUES (2,'Vijay'), (3, 'Other name'), (2, 'Extra name')
SELECT 'multiple insert', * FROM ContactInfo
GO

-- update should not affect primary
update ContactInfo SET ContactName = 'new name for non primary #1' where CompanyID = 2
SELECT 'update non primary', * FROM ContactInfo
GO

update ContactInfo SET ContactName = 'new name for primary' where CompanyID = 1
SELECT 'update primary', * FROM ContactInfo
GO

-- deleting existing primary
delete ContactInfo WHERE ID = 2
SELECT 'delete primary', * FROM ContactInfo
GO

-- try to remove primary from existing record
update ContactInfo SET IsPrimary = 0 where ID = 1
SELECT 'remove primary', * FROM ContactInfo

-- multiple deletes
DELETE ContactInfo
WHERE CompanyID IN (2, 3)
SELECT 'multiple delete, including primary', * FROM ContactInfo

-- insert another record with primary
INSERT INTO ContactInfo (CompanyID,ContactName, IsPrimary) VALUES (2,'Other primary', 1)
SELECT 'insert another record with primary', * FROM ContactInfo
GO

-- try to force primary for multiple records
INSERT INTO ContactInfo (CompanyID,ContactName, IsPrimary) VALUES (1,'Vijay #2', 1), (1, 'Other name #2', 1)
SELECT 'multiple insert with primary', * FROM ContactInfo
GO
这强制执行条件1


我建议您从应用程序或通过storedp程序强制执行条件2、3、4。触发器通常会产生意想不到的副作用

您需要实施触发器。你试过什么?您能显示代码吗?我计划这样做-对于新插入,如果未选择主如果不存在从ContactInfo中选择isprimary,其中CompanyID=1和isprimary=1开始更新ContactInfo SET isprimary=1end@naweez我真的不明白你在这里。我觉得扳机没问题。您能描述一下它不起作用的情况吗?您可以只对插入和删除的表进行联合,而不必担心混淆逻辑iPrimary的设计是不合适的,您不应该依赖触发器来维护字段并遭受可能的锁定。而是添加一个CreateDate字段和ForcePrimaryDate,然后从一个视图动态计算iPrimary。我希望用户在插入和更新时必须进行选择。如果用户删除了iPrimary记录,则可以将iPrimary顶部的一条记录分配给用户。测试的最后一次插入显示用户可以指定iPrimary。IsPrimary位于第一条记录上,用户尝试插入两个IsPrimary值。第一条记录不再是主记录,第二条记录是主记录。我还将使用IsPrimary添加一个简单插入测试,以表明IsPrimary可以以确定的方式移动。我终于看到了问题真正想从我们这里得到什么,因此我更改了触发器以相应地采取行动。我仍然不确定它是否匹配所有场景,但它允许配置iPrimary在组中不存在或存在重复项时的行为。我可以通过约束防止使用,但我需要自动。触发器是唯一能自动执行的东西,但它们通常会变成维护的噩梦。
truncate table ContactInfo
go

-- first records should be primary
INSERT INTO ContactInfo (CompanyID,ContactName) VALUES (1,'Some name 1'), (2, 'Some name 2')
SELECT 'first records', * FROM ContactInfo
GO

-- multiple insert - should not get primary
INSERT INTO ContactInfo (CompanyID,ContactName) VALUES (2,'Vijay'), (3, 'Other name'), (2, 'Extra name')
SELECT 'multiple insert', * FROM ContactInfo
GO

-- update should not affect primary
update ContactInfo SET ContactName = 'new name for non primary #1' where CompanyID = 2
SELECT 'update non primary', * FROM ContactInfo
GO

update ContactInfo SET ContactName = 'new name for primary' where CompanyID = 1
SELECT 'update primary', * FROM ContactInfo
GO

-- deleting existing primary
delete ContactInfo WHERE ID = 2
SELECT 'delete primary', * FROM ContactInfo
GO

-- try to remove primary from existing record
update ContactInfo SET IsPrimary = 0 where ID = 1
SELECT 'remove primary', * FROM ContactInfo

-- multiple deletes
DELETE ContactInfo
WHERE CompanyID IN (2, 3)
SELECT 'multiple delete, including primary', * FROM ContactInfo

-- insert another record with primary
INSERT INTO ContactInfo (CompanyID,ContactName, IsPrimary) VALUES (2,'Other primary', 1)
SELECT 'insert another record with primary', * FROM ContactInfo
GO

-- try to force primary for multiple records
INSERT INTO ContactInfo (CompanyID,ContactName, IsPrimary) VALUES (1,'Vijay #2', 1), (1, 'Other name #2', 1)
SELECT 'multiple insert with primary', * FROM ContactInfo
GO
CREATE UNIQUE NONCLUSTERED INDEX UIX_IsPrimary ON ContactInfo
(
    CompanyID ASC
)
WHERE (IsPrimary=(1))
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, 
DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, 
ALLOW_PAGE_LOCKS  = ON) 
ON [PRIMARY]