SQL Server:使用多列外键创建表

时间:2014-01-06 16:55:24

标签: sql sql-server foreign-keys multiple-columns create-table

我必须在SQL Server中创建一组表。

那些是:

  • chips,用于识别植入动物的芯片
  • signals,因为每个芯片每小时产生一次信号
  • signal receivers,如果芯片处于半径范围内,可以接收信号的电台
  • signal receivings,用于接收方已收到的信号

我在创建这些表时遇到问题。

这是我的代码:

CREATE TABLE CHIPS (
    ID INT PRIMARY KEY,
    ...(not related attributes)...
    );

CREATE TABLE RECEIVERS (
    ID_receiver INT PRIMARY KEY,
    ...(some other attributes, not related to the problem)...
    );

CREATE TABLE SIGNALS (
    ID_chip INT FOREIGN KEY REFERENCES CHIPS, 
    Signal_no INT, 
    Date DATETIME, 
    PRIMARY KEY (ID_chip, Signal_no)
    );

CREATE TABLE SIGNAL_RECEIVINGS (
    ID_receiver INT REFERENCES RECEIVERS ,
    Id_chip INT REFERENCES SIGNALS(ID_chip), 
    Signal_no INT REFERENCES SIGNALS(Signal_no), 
    PRIMARY KEY (Id_chip, Signal_no, ID_receiver ) 
    );

我的问题是我不知道如何为SIGNAL_RECEIVERS制作正确的密钥。我希望它是(Id_chip, Signal_no, ID_receiver),因为只有这样才会是唯一的,但SQL会输出错误:

  

外键' FK__SIGNAL_R__Si_no__5C187C73'的引用列列表中的列数与引用表格中的主键不匹配' SIGNALS'。

有人可以帮我解决这个问题吗?

3 个答案:

答案 0 :(得分:6)

您的问题不在SIGNAL_RECEIVINGS的主键上,这样就可以了。您的问题是,id_chip包含SIGNALS的外键,Signal_no包含SIGNALS的外键,两者都引用单个列。鉴于SIGNALS上的PK是一个复合键,SIGNAL_RECEIVINGS上的FK也必须是该表的组合。

您需要创建一个FK,指向两列:

CREATE TABLE SIGNAL_RECEIVINGS (
  ID_receiver INT REFERENCES RECEIVERS ,
  Id_chip INT, 
  Signal_no INT, 
  Foreign Key (id_chip, signal_no) references Signals (id_chip, signal_no),
  PRIMARY KEY (Id_chip, Signal_no, ID_receiver ) 
  );

那就是说,我认为你对复合主键的使用将会失控,就像你在整个地方使用它们一样。很快(继续使用您已有的代码),您将最终得到可能长达数十列的复合键。我将引导您this回答另一个问题,详细说明为什么简单地在代码中添加一个Identity列将有助于简化您的密钥。

复合键在数据必须出现多个位置的地方非常方便,但如果您只是为了满足键约束而添加这些列,那么单个Identity列会更适合。

答案 1 :(得分:2)

1)包含可空列的复合FK 非常棘手,因为它们允许孤立行。

示例:

CREATE TABLE dbo.X (
    ColA INT not null,
    ColB INT not null,
    PRIMARY KEY (ColA, ColB)
);
CREATE TABLE dbo.Y (
    ColA int null,
    ColB int null,
    FOREIGN KEY(cola, colb)
    REFERENCES dbo.X(ColA, ColB)
);
INSERT dbo.Y VALUES (NULL,123);
GO
/*
(1 row(s) affected)
*/

SELECT * FROM dbo.Y 
ColA        ColB
----------- -----------
NULL        123

如您所见,即使我们在dbo.X(PK)中没有任何行,我们也有一个[孤儿]行进入dbo.Y(FK)。这是可能的,因为我们已将NULL插入ColA。因此,如果我们希望SQL Server在这种情况下检查参照完整性(具有可空列的复合FK),则复合外键的所有值必须为NOT NULL(在此示例中为ColA和ColB)。

2)因此有3个选项:(i)您的业务允许此类孤立行,(ii)您在强制(NOT NULL)列上创建复合FK

CREATE TABLE dbo.SIGNAL_RECEIVINGS (
  ID_receiver INT REFERENCES dbo.RECEIVERS(ID_receiver) ,
  Id_chip INT NOT NULL,     -- Mandatory column
  Signal_no INT NOT NULL,   -- Mandatory column
  FOREIGN KEY (id_chip, signal_no) REFERENCES dbo.Signals (id_chip, signal_no),
  ...
);

或(iii)您创建一个简单的FK。

答案 2 :(得分:1)

试试这个:

CREATE TABLE SIGNAL_RECEIVINGS (
ID_receiver INT REFERENCES RECEIVERS ,
Id_chip INT  , 
Signal_no INT , 
PRIMARY KEY (Id_chip, Signal_no, ID_receiver ) ,
foreign key (id_chip,signal_no) references signals(id_chip,signal_no)
);