我必须在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'。
有人可以帮我解决这个问题吗?
答案 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)
);