我有一个数据库,我试图使用外键确保参照完整性,但我不确定如何继续:
共有四个表:公司,员工,订单和BillingCode。
公司有多名员工,每个员工都可以下订单。 必须为每个订单分配一个帐单代码 - 来自查询表。 每家公司都可以有多个帐单代码 员工只能使用分配给公司的帐单代码。
基本图表:http://i61.tinypic.com/21bm937.png
CREATE TABLE [dbo].[BillingCodes](
[BillingId] [int] NOT NULL,
[CompanyId] [int] NOT NULL,
[BillingCode] [varchar](10) NOT NULL,
CONSTRAINT [PK_BillingCodes] PRIMARY KEY CLUSTERED
(
[BillingId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Company](
[CompanyId] [int] NOT NULL,
[CompanyName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Company] PRIMARY KEY CLUSTERED
(
[CompanyId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Employees](
[EmployeeId] [int] NOT NULL,
[CompanyId] [int] NOT NULL,
[Name] [varchar](50) NOT NULL
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED
(
[EmployeeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Orders](
[OrderId] [int] NOT NULL,
[EmployeeId] [int] NOT NULL,
[Price] [money] NOT NULL,
[Qty] [int] NOT NULL,
[BillingId] [int] NOT NULL,
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
[OrderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[BillingCodes] WITH CHECK ADD CONSTRAINT [FK_BillingCodes_Company] FOREIGN KEY([CompanyId])
REFERENCES [dbo].[Company] ([CompanyId])
GO
ALTER TABLE [dbo].[Employees] WITH CHECK ADD CONSTRAINT [FK_Employees_Company] FOREIGN KEY([CompanyId])
REFERENCES [dbo].[Company] ([CompanyId])
GO
ALTER TABLE [dbo].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Employees] FOREIGN KEY([EmployeeId])
REFERENCES [dbo].[Employees] ([EmployeeId])
GO
如何确保[订单]中的[BillingId]与员工在同一家公司?
通常,我只需在[BillingId]上的[BillingCodes]和[Orders]之间创建一个外键,并在业务层中强制执行[CompanyId]引用。不幸的是,在这种情况下,我有一个老板喜欢进入数据库并手动更正数据。所以我需要在数据库中强制执行此操作。
我唯一的选择是将CompanyID带到订单表,并使用复合外键来[BillingCode]?这是一个简化版本 - [公司]和[员工]之间还有另外3个表格,所以如果我不需要,我不会在每个表格中都有[CompanyId]。
有没有更简单的方法来实现这一目标?
答案 0 :(得分:1)
另一种方法是在Orders上添加插入和更新的触发器。这将验证BillingId是否与EnployeeId所在的同一公司相关联。如果他们最终在不同的公司,然后提出错误。这可能就是我这样做的方式。
答案 1 :(得分:0)
你可以仅使用参照完整性约束来实现这一点,它只需要一些冗余 - 这并不是一件坏事。
首先,您必须将CompanyID和EmployeeID一起带到Orders表,并使其可以引用到Employee表。
alter table Employees add unique constraint UQ_Employee_Co( EmployeeID, CompanyID );
alter table BillingCodes add unique constraint UQ_BillingCodes_Company_Code( BillingID, CompanyID );
-- Or use indexes - no matter.
CREATE TABLE Orders(
OrderId int NOT NULL,
EmployeeId int NOT NULL,
CompanyID int not null,
Price money NOT NULL,
Qty int NOT NULL,
BillingId int NOT NULL,
CONSTRAINT PK_Orders PRIMARY KEY( OrderID ),
constraint FK_Orders_Employee foreign key( EmployeeID, CompanyID )
references Employees( EmployeeID, CompanyID ),
constraint FK_Orders_BillingCode foreign key( BillingID, CompanyID )
references BillingCodes( BillingID, CompanyID ),
);
现在,您不能拥有与一家公司关联的EmployeeID和与另一家公司关联的BillingID的订单,因为您不能拥有与EmployeeID和CompanyID不匹配的订单。员工表,也不是与BillingCodes表中的内容不匹配的CompanyID和BillingID。
所有这些都是你需要的一个额外专栏。