0

我有一个 SQL Server 表:

+----+-------------+-------------------+
| ID | CompanyID   | CompanyCode       |
+----+-------------+-------------------+
| 1  | 1           | AAAA-123          |
| 2  | 2           | BBBB-111          |
| 3  | 1           | AAAA-123          |
| 4  | 3           | CCCC-999          |
| 5  | 3           | CCCC-999          |
| 6  | 1           | AAAA-123          |
+----+-------------+-------------------+

ID领域是PK 。

CompanyIDCompanyCode字段指定一个独特的公司,其中 a willCompanyID总是具有相同的CompanyCode(反之亦然),并且没有两家公司将具有相同的CompanyID和/或CompanyCode

我想在表上创建一个规则,如果/当 a与'匹配的现有位置CompanyCode不匹配时,将永远不允许将记录添加到表中。CompanyCodeCompanyID

以下是我不允许在桌子上发生的示例:

+----+-------------+-------------------+
| ID | CompanyID   | CompanyCode       |
+----+-------------+-------------------+
| 1  | 1           | AAAA-123          |
| 2  | 1           | BBBB-111          |<<<< This record should not be allowed
| 3  | 1           | AAAA-123          |
| 4  | 3           | CCCC-999          |
| 5  | 3           | CCCC-999          |
| 6  | 1           | AAAA-123          |
+----+-------------+-------------------+

请注意带有 的记录 与带有ID=2CompanyCode BBBB-111现有记录不匹配CompanyCode of AAAA-123

我希望这条规则以某种方式存在于表中——即我不希望这条规则成为查询和/或存储过程必须管理的业务规则。

我想你可以说当且仅当表中存在和/或存在时,我想强制执行重复记录(onCompanyID和)。CompanyCodeCompanyIDCompanyCode

这可以在表格设计级别进行吗?还是我不得不在我的脚本中管理这个?

更新

虽然这与我的 OP 并不真正相关,但从我收到的反馈来看,我想我应该提供一点关于 CompanyID/CompanyCode 表设计的背景知识。

首先,这只是一个模拟表设计,试图解释我的问题——我的真实表与公司无关。

其次,我的真实表是两个 Web 服务之间的中间人,其中 Service1 创建一个DeviceID,Service2收集一个SerialNumber存在于微设备中的。此外,我的真实表包含该中间人服务器必须处理的许多其他列。

关于这个中间人服务的一个奇怪的事情是,我正在谈论的表必须允许 DeviceID 和 SerialNumber 为 NULL - 这完全取决于哪个服务首先发送了一条记录......我是谈论太多并且偏离了我原来的问题的主题,但我认为我必须澄清我的表格示例,因为我对打破正常化感到非常不满。

4

5 回答 5

4
 CREATE UNIQUE INDEX idx_name ON TableName(CompanyID, CompanyCode)

(假设您的表名为 TableName)。

但是,您应该知道,这种设计违反了数据库规范化的原则。正确规范化的数据库将有一个单独的表,其中仅包含 CompanyID 和 CompanyName 字段。然后,您将修改示例中的表以仅包含 CompanyID 字段;CompanyCode 将在需要时“查找”(使用 VIEW)。

这种设计有以下好处:

  1. 从字面上看,不可能拥有具有不同名称的相同公司 ID。

  2. 如果公司更改其代码,您只需更新单个表中的一条记录,这样可以防错且速度更快。

  3. 您节省存储空间。

它有一个小缺点,您必须加入 Company 表才能获取代码。在关系数据库中,这不一定是一个真正的缺点(加入规范化数据是关系数据库的用途),但您甚至可以通过摆脱 CompanyID 并将代码用作公司的主键来消除这种情况。如果代码是不可变的(对于给定的公司,它不会随着时间的推移而改变),我只会考虑这一点。

于 2012-04-04T12:46:48.030 回答
2

我建议您不要将 CompanyID 和 CompanyCode 存储在表中。相反,您应该有另一个表,该表为每个 CompanyId 存储 1 行,并且还具有相应的代码。然后,您可以设置一个外键以确保该表中的 CompanyId 存在于另一个表中。

于 2012-04-04T12:48:12.333 回答
2

我不知道制定规则来强制执行此操作,但您正在为同一件事使用两个单独的外键(这将始终匹配)......在此表中没有公司代码会是一个更好的主意全部并在需要数据时将其连接到不同的表中,或以其他方式重新设计

于 2012-04-04T12:49:36.837 回答
0

好的,这不是最漂亮的代码,但我认为它确实强制执行了约束。诀窍是创建一个索引视图,其中定义了两个唯一索引:

create table dbo.ABC (
    Col1 int not null,
    Col2 int not null
)
go
create view dbo.ABC_Col1_Col2_dep
with schemabinding
as
    select Col1,Col2,COUNT_BIG(*) as Cnt
    from
        dbo.ABC
    group by
        Col1,Col2
go
create unique clustered index IX_Col1_UniqueCol2 on dbo.ABC_Col1_Col2_dep (Col1)
go
create unique nonclustered index IX_Col2_UniqueCol1 on dbo.ABC_Col1_Col2_dep (Col2)
go

现在我们插入一些初始数据:

insert into dbo.ABC (Col1,Col2)
select 1,3 union all
select 2,19 union all
select 3,12

Col1我们可以为and添加另一行具有完全相同的值Col2

insert into dbo.ABC (Col1,Col2)
select 1,3

但是,如果我们选择一个Col2已用于另一个的值Col1,反之亦然,我们会得到错误:

insert into dbo.ABC (Col1,Col2)
select 2,3
go
insert into dbo.ABC (Col1,Col2)
select 1,5

这里的诀窍是观察这个查询:

    select Col1,Col2,COUNT_BIG(*) as Cnt
    from
        dbo.ABC
    group by
        Col1,Col2

将只有一行用于特定Col1值,并且只有一行具有特定Col2值,前提是您要强制执行的约束没有被破坏 - 但只要将不匹配的行插入基表,此查询返回多行。

于 2012-04-04T14:42:02.063 回答
0

你违反了第三范式。一个非键依赖于另一个非键。CompanyCode 取决于 CompanyID。其他人所说的补救措施是创建一个CompanyID,CompanyCode表,其中CompanyID是PK。从您的表中删除 CompanyCode 并在 ComanyID 上创建指向您新表的 FK 关系。 http://www.phlonx.com/resources/nf3/ http://en.wikipedia.org/wiki/Third_normal_form

于 2012-04-04T13:50:06.793 回答