【问题标题】:UNIQUE CONSTRAINT on a column from foreign table in SQL Server 2008SQL Server 2008 中外部表中列的唯一约束
【发布时间】:2010-06-12 23:03:51
【问题描述】:

我有两张桌子:


create table [dbo].[Main]
(
    [ID] [int] identity(1,1) primary key not null,
    [No] [int] not null,
    [Sign] [char](1) not null
)

create table [dbo].[Names]
(
    [ID_Main][int] primary key not null,
    [Name][nvarchar](128) not null,
    constraint [FK_Main_Users] foreign key ([ID_Main]) references [dbo].[Main]([ID]),
    constraint [CK_Name] unique ([Name], [Sign])
)

问题在于第二个约束 CK_Name

有没有办法从外部表中创建一个约束目标列?



编辑:



说明。 我在使用 EntityFramework 的 Silverlight 应用程序中使用这些表。 实体是由 Table 每个类型继承创建的,所以代码是这样的:


public abstract class Main
{
    // main properties
}

public class Names : Main
{
    // names properties
}

这迫使我不要使用 sql 视图。

样本数据。

--------------------------------------------- |主要 |姓名 | --------------------------------------------- |身份证 |登录 |没有 | ID_Main |姓名 | --------------------------------------------- | 1 |一个 | 1 | 1 | 'qwe' | | 2 |乙| 1 | 2 | 'qwe' | | 3 |乙| 1 | 3 | 'qwe' | | 4 | C | 1 | 4 | 'qwe' | | 5 |一个 | 2 | 5 | 'asd' | | 6 |乙| 2 | 6 | 'asd' | | 7 |乙| 2 | 7 | 'asd' | | 8 | C | 2 | 8 | 'asd' |

如您所见,有些行名称相同但符号不同。 不能有任何具有相同标志的非唯一名称。

我想强制只有一个带有符号 = A 的名称和只有一个带有符号 C 的名称 但是很多名字带有Sign = B

【问题讨论】:

  • 为什么不在[Name, ID_Main][Sign][Main] 表中的其他唯一?
  • 鉴于您提供的其他信息,我想进一步了解您为什么需要此限制。 MainNames 代表什么实体?给定示例输出,Names 表看起来像一个中间表,但 ID_Main 是一个 PK,因此它实际上是作为 1:1 关系执行的。一个标志只能有一个名字而另一个标志可以有多个名字的规则是什么?
  • 几乎我系统中的每个表都有几个公共列,所以我将它们放在一个主表中,其他表引用它们。是的,这似乎是 1:1 的关系,但其他一些逻辑使它成为 1:* 但不是直接的
  • 这是 SQL,而不是 OOP,其概念在基于 SET 的环境中没有实际意义。
  • 正如 OMG Ponies 所说,关系模型与 OOP 不同。您不能创建一个基表来为所有其他表统治它们。暂时忘记属性(列),从系统中存在的主要实体开始。通常,每个实体都会有自己的表。

标签: sql sql-server tsql constraints unique


【解决方案1】:

是的,您可以使用索引视图强制执行此类约束,并在 (Sign, Name) 上为过滤的结果集创建唯一约束(索引)。

CREATE VIEW dbo.vwSelectiveUniqueSignName WITH SCHEMABINDING
AS
SELECT  [Sign], Name
FROM    
    dbo.Main INNER JOIN dbo.Names on ID = ID_Main
WHERE
    dbo.Main.Sign IN ('A', 'C')
GO

CREATE UNIQUE CLUSTERED INDEX IDX_vwSelectiveUniqueSignName_Unique_Sign_Name
    ON dbo.vwSelectiveUniqueSignName ( [Sign] ASC, Name ASC )
GO

测试:

-- using your sample data:
/* Case 1 Sign = 'A', Name = 'qwe': this will throw error 'cannot insert duplicate key row in object ... with unique index ... */
BEGIN TRAN NotAllowedMoreThan_1
insert dbo.Main ([Sign]) OUTPUT inserted.* values ('A') /* same for 'C' */
insert dbo.Names (ID_Main, Name) OUTPUT inserted.* SELECT SCOPE_IDENTITY(),'qwe'
COMMIT TRAN NotAllowedMoreThan_1
GO

/* Case 2 Sign = 'B', Name = 'qwe': this will pass > 1 times (note GO loop) */
BEGIN TRAN AllowedMoreThan_1
insert dbo.Main ([Sign]) OUTPUT inserted.* values ('B') /* any other than A, C */
insert dbo.Names (ID_Main, Name) OUTPUT inserted.* SELECT SCOPE_IDENTITY(),'qwe'
COMMIT TRAN AllowedMoreThan_1
GO 2

【讨论】:

  • 我已经编辑了我的帖子并提供了更多解释。即使我不使用视图,对视图的约束也有效?
  • 是的,约束将阻止向表中插入非唯一记录。
  • 好的,您的回答和这篇帖子dbwhisperer.blogspot.com/2008/11/… 帮助我找到了解决问题的方法。如果您愿意并编辑您的帖子,更改视图定义,使其仅显示带有“A”的行中的名称并在其上添加唯一索引,我会将其标记为答案
  • 我已经编辑了关于您的编辑和解释的答案,并包含了对您的示例数据运行测试的代码。
【解决方案2】:

要回答您的问题,无法在检查约束(或任何其他类型的约束)中引用外部表中的列。但是,在您的情况下,您希望确保 Names.NameMain.Sign 的任何组合都是唯一的。为此,您只需在两列中的每一列上添加一个唯一约束:

Alter Table dbo.Main Add Constraint UC_Main Unique Nonclustered ( Sign )
GO
Alter Table dbo.Names Add Constraint UC_Names Unique Nonclustered ( Name )

没有必要对 ID_Main 和 Name 一起创建唯一约束,因为 ID_Main 已经通过其主键约束被要求是唯一的。

【讨论】:

    猜你喜欢
    • 2013-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多