2013-04-09 71 views
0

我需要SQL Server中约束的帮助。情况是针对表上的每个OrderID = 1(外键不是主键,因此有多个具有相同ID的行),位字段对于其中一个行只能是1,对于OrderID = 2的每行,位字段对于一行只能是1等等。对于具有相同OrderID的所有其他行,它应该是0。如果已有一行OrderID具有位域设置为1的任何新记录,则在位域中以1进入的新记录应拒绝。任何想法?SQL Server约束(基于外键的限制位字段)

+0

如果非答案适合您,尤其是在2008年以前的版本中,您可以编写插入/更新触发器来拒绝重复项 – Mark 2013-04-10 10:10:17

回答

1

你可以更完全地标准化模式,这将帮助你不必寻找已经设置的位,但使用连接。你需要删除位字段并创建一个新的表,表示X包含OrderID和表的主键,X的主键是所有这些字段。

这意味着,当您插入时,您需要插入到原始表格和X f中,并且仅当您将该表格设置为1时。如果X中已经有一行,就好像已经有一个原始行的位已设置为1,则插入将失败。

缺点是,这占用了比您的模式更多的空间,但更容易维护为您无法达到将该位设置为1的两行的等价物。

+0

如果必须更改表结构,我会牢记这一点。谢谢! – user2263882 2013-04-11 16:59:37

0

要做到这一点的唯一方法是对父表进行子类化。你没有提到它,但是这种模式的一个常见原因是从具有相同公共键值的所有行集合中表示一个唯一的活动行。让我们假设你的位字段表示活跃订单.... 然后,我会创建一个名为ActiveOrders一个单独的表,其中只包含设置为1

Create Table ActiveOrders(int Orderid Primary Key Null) 
位域一行

和其他表所有在它的行,与它自己唯一的主键的OrderId

Create Table AllOrders 
(OrderId Integer Primary Key Not Null, ActiveOrderId Integer Not Null, 
[All other data fields] 
Constraint FK_AllOrders2ActiveOrder 
    Foreign Key(ActiveOrderId) references ActiveOrders(OrderId)) 

您现在不再需要位域,因为ActiveOrders表中的行的存在将其标识为活动订单...要仅获取活动订单(在您的方案中将位域设置的订单到1),只需加入两张表。

+0

谢谢,这是一个很好的建议。我暂时不想改变桌子的结构,但我会牢记这一点。 – user2263882 2013-04-11 16:58:33

0

我同意其他答案,如果你可以改变模式然后做,但如果没有,那么我认为这样的事情会做。

CREATE FUNCTION fnMyCheck 
    (@id INT) 
RETURNS INT 
AS 
BEGIN 
    DECLARE @i INT 

    SELECT @i = COUNT(*) 
    FROM MyTable 
    WHERE FkCol = @id 
    AND BitCol = 1 

    RETURN @i 
END 

ALTER TABLE YourTable 
ADD CONSTRAINT ckMyCheck CHECK (fnMyCheck(FkCol)<=1) 

,但也有可能来自使用检查约束一个UDF做题,如this

编辑添加评论有关问题与本“解决方案”:

有比您所链接的更直接的问题。

INSERT INTO YourTable(FkCol,BitCol) VALUES (1,1),(1,0) 

其次

UPDATE YourTable SET BitCol=1 

成功,并留下两排FkCol = 1和BitCol = 1

+1

有比您链接到的更直接的问题。在INSERT INTO YourTable(FkCol,BitCol)VALUES(1,1),(1,0)'后面加上'UPDATE YourTable SET BitCol = 1'成功并留下两行,'FkCol' = 1且'BitCol' = 1 – 2013-04-10 06:47:29

2
CREATE UNIQUE INDEX ON UnnamedTable (OrderID) WHERE UnnamedBitField=1 

它被称为Filtered Index。如果您使用的是2008年之前的版本的SQL Server,你可以使用索引视图实现过滤指数的差芒相当于:

CREATE VIEW UnnamedView 
WITH SCHEMABINDING 
AS 
    SELECT OrderID From UnnamedSchema.UnnamedTable WHERE UnnamedBitField=1 
GO 
CREATE UNIQUE CLUSTERED INDEX ON UnnamedView (OrderID) 

你不能真正做到这一点作为一个约束,因为SQL Server仅支持列约束和行约束。没有(非欺骗性)的方式来编写处理表中所有值的约束。

+0

我正在使用SQL Server 2000(难过,我知道),所以我使用了索引视图,这对我很有用。唯一的区别是我不得不使用“CREATE UNIQUE CLUSTERED INDEX”而不是“CREATE UNIQUE INDEX”。谢谢! – user2263882 2013-04-11 16:53:21

+0

@ user2263882 - 我已经更新了样本(我承认,我没有必要使用这些努力多年并从内存中工作)。 – 2013-04-11 17:03:11