SQL Server 2008中外表的列上的UNIQUE CONSTRAINT

时间:2010-06-12 23:03:52

标签: sql sql-server tsql constraints unique

我有两张桌子:


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 per type inheritance创建的,所以代码是这样的:


public abstract class Main
{
    // main properties
}

public class Names : Main
{
    // names properties
}

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

样本数据。

---------------------------------------------
|  Main                |  Names             |
---------------------------------------------
|  ID  |  Sign  |  No  |  ID_Main  |  Name  |
---------------------------------------------
|   1  |     A  |   1  |    1      |  'qwe' |
|   2  |     B  |   1  |    2      |  'qwe' |
|   3  |     B  |   1  |    3      |  'qwe' |
|   4  |     C  |   1  |    4      |  'qwe' |
|   5  |     A  |   2  |    5      |  'asd' |
|   6  |     B  |   2  |    6      |  'asd' |
|   7  |     B  |   2  |    7      |  'asd' |
|   8  |     C  |   2  |    8      |  'asd' |

正如您所看到的,有些行具有相同的名称但具有不同的符号。 不能有任何具有相同Sign的非唯一Name。

我想强制执行只有一个名称带有Sign = A且只有一个带有Sign C的名称 但很多名字有Sign = B

2 个答案:

答案 0 :(得分:4)

是的,您可以使用索引视图强制执行此类约束,并为筛选的结果集在(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

答案 1 :(得分:1)

要回答您的问题,无法在检查约束(或任何其他类型的约束)中引用外表中的列。但是,在您的情况下,您需要确保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已经要求通过其主键约束是唯一的。