一个表不能有两个字段同时外键关联另外同一个表?

Aricc 2018-07-24 08:23:27

CREATE TABLE [dbo].[T_Follow] (
[FollowerID] [nvarchar](128) NOT NULL,
[LeaderID] [nvarchar](128) NOT NULL,
[FollowDate] [datetime] NOT NULL,
CONSTRAINT [PK_dbo.T_Follow] PRIMARY KEY ([FollowerID], [LeaderID])
)
CREATE INDEX [IX_FollowerID] ON [dbo].[T_Follow]([FollowerID])
CREATE INDEX [IX_LeaderID] ON [dbo].[T_Follow]([LeaderID])
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_FollowerID] FOREIGN KEY ([FollowerID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE CASCADE
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_LeaderID] FOREIGN KEY ([LeaderID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE CASCADE

如上脚本,SQL SERVER会有如下错误提示:
消息 1785,级别 16,状态 0,第 10 行
将 FOREIGN KEY 约束 'FK_dbo.T_Follow_dbo.T_User_LeaderID' 引入表 'T_Follow' 可能会导致循环或多重级联路径。请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
消息 1750,级别 16,状态 0,第 10 行
无法创建约束。请参阅前面的错误消息。

我在Oracle中测试同样场景,没有问题:

-- Create table
create table TA
(
id varchar2(40) not null,
name varchar2(40)
)
;
-- Create/Recreate primary, unique and foreign key constraints
alter table TA
add constraint PK_TA_ID primary key (ID);

----------

-- Create table
create table TB
(
f_aid varchar2(40),
l_aid varchar2(40)
)
;
-- Create/Recreate primary, unique and foreign key constraints
alter table TB
add constraint FK_F_AID foreign key (F_AID)
references ta (ID) on delete cascade;

alter table TB
add constraint FK_L_AID foreign key (L_AID)
references ta (ID) on delete cascade;
...全文
508 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
zbdzjx 2018-07-24
  • 打赏
  • 举报
回复
提到外键,想起当年论文答辩时,几个教授就争论起外键的好坏了。
网上看到的:数据量不是特别大时,外键的优势大于劣势;数据量大了,劣势就大于优势了。
丰云 2018-07-24
  • 打赏
  • 举报
回复
说到这里,顺便就说下生产环境的现在的一般做法

那就是数据库只单纯的做数据存取,不做业务处理

也就是说,数据库里,最好不要关系,不要约束,不要触发器,不要过程

业务有代码维护。

这其实也是一种解耦,这样做的好处非常多,大家可以仔细体会。

尤其是立志于做架构设计师的
丰云 2018-07-24
  • 打赏
  • 举报
回复
引用 2 楼 Aricc 的回复:
[quote=引用 1 楼 yenange 的回复:]
到什么山唱什么歌吧。 不是 oracle 允许的, sqlserver 一定就得允许。
改一下不就好了:
CREATE TABLE T_User(
UserID [nvarchar](128) PRIMARY KEY,
UserName NVARCHAR(20)
)

CREATE TABLE [dbo].[T_Follow] (
[FollowerID] [nvarchar](128) NOT NULL,
[LeaderID] [nvarchar](128) NOT NULL,
[FollowDate] [datetime] NOT NULL,
CONSTRAINT [PK_dbo.T_Follow] PRIMARY KEY ([FollowerID], [LeaderID])
)
CREATE INDEX [IX_FollowerID] ON [dbo].[T_Follow]([FollowerID])
CREATE INDEX [IX_LeaderID] ON [dbo].[T_Follow]([LeaderID])
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_FollowerID] FOREIGN KEY ([FollowerID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE no ACTION;
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_LeaderID] FOREIGN KEY ([LeaderID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE no ACTION;


另外, 设置显式的外键, 其实在生产环境是大忌, 一般不要做这个事。只有学生才搞这个玩意。

划山头,拉帮结派,不是好做法。
难道搞Sql Server了就不能用Oracle了吗?
只是做个对比,同时根本的我是想知道SQL Server有这个约束的原因。

另外,我也知道改为ON DELETE no ACTION就可以了。

对于“设置显式的外键, 其实在生产环境是大忌”不敢苟同,照这么说,外键这个东西,它存在的意义是什么?
[/quote]
我觉得一楼说的很对哦
不是说非要话山头,这只是个比方。
没有谁硬性要求所有关系型数据库,必须全部严格遵循标准T-SQL语法。
每个数据库有自己的一些特色很正常。

何况sql server不允许出现循环引用的数据定义,
其实是好意,既遵循了集合论的一般原则,也是跟他自己的ado对象保持畅通的数据交换通道有关。

并且,生产环境中,业务非常复杂,且经常修改调整,如果所有数据都严格对象化和关系化,
在适应性和可维护性上就大受局限,
甚至可能带来非常痛苦的体验,
这些只有尽力过的人才能理解。

所以我们平时总是说,不用严格满足五范式,满足三范式就够了,
甚至在三范式的基础上,还允许部分冗余,这都是有道理的


吉普赛的歌 2018-07-24
  • 打赏
  • 举报
回复
有些东西没法追根到底的, 意义不大。
比方说, 计算列在 sqlserver 里面, 早在 2000 版就有了, 但 mysql 直到 5.7 才出来, 用习惯了 sqlserver 计算列的人, 转到 mysql 去是不是得把 mysql 的开发者骂死?

至于为什么, 你贴出来的错误信息也有“可能会导致循环或多重级联路径”

外键在生产环境是大忌,
一方面是数据迁移、归档。你要实际做数据迁移, 归档之类的操作, 才会有深刻体会。
另外, 只要是约束, 必然影响效率, 外键约束的恶劣影响, 比其它约束要强得多, 因为它关联了不相干的表,导致锁更加复杂, 更加容易产生堵塞和死锁。这在并发量大、操作频繁的情况下是 致命 的。
外键约束, 尽量在程序里完成相关的检查和操作。
Aricc 2018-07-24
  • 打赏
  • 举报
回复
引用 1 楼 yenange 的回复:
到什么山唱什么歌吧。 不是 oracle 允许的, sqlserver 一定就得允许。
改一下不就好了:
CREATE TABLE T_User(
UserID [nvarchar](128) PRIMARY KEY,
UserName NVARCHAR(20)
)

CREATE TABLE [dbo].[T_Follow] (
[FollowerID] [nvarchar](128) NOT NULL,
[LeaderID] [nvarchar](128) NOT NULL,
[FollowDate] [datetime] NOT NULL,
CONSTRAINT [PK_dbo.T_Follow] PRIMARY KEY ([FollowerID], [LeaderID])
)
CREATE INDEX [IX_FollowerID] ON [dbo].[T_Follow]([FollowerID])
CREATE INDEX [IX_LeaderID] ON [dbo].[T_Follow]([LeaderID])
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_FollowerID] FOREIGN KEY ([FollowerID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE no ACTION;
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_LeaderID] FOREIGN KEY ([LeaderID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE no ACTION;


另外, 设置显式的外键, 其实在生产环境是大忌, 一般不要做这个事。只有学生才搞这个玩意。

划山头,拉帮结派,不是好做法。
难道搞Sql Server了就不能用Oracle了吗?
只是做个对比,同时根本的我是想知道SQL Server有这个约束的原因。

另外,我也知道改为ON DELETE no ACTION就可以了。

对于“设置显式的外键, 其实在生产环境是大忌”不敢苟同,照这么说,外键这个东西,它存在的意义是什么?
吉普赛的歌 2018-07-24
  • 打赏
  • 举报
回复
到什么山唱什么歌吧。 不是 oracle 允许的, sqlserver 一定就得允许。
改一下不就好了:
CREATE TABLE T_User(
UserID [nvarchar](128) PRIMARY KEY,
UserName NVARCHAR(20)
)

CREATE TABLE [dbo].[T_Follow] (
[FollowerID] [nvarchar](128) NOT NULL,
[LeaderID] [nvarchar](128) NOT NULL,
[FollowDate] [datetime] NOT NULL,
CONSTRAINT [PK_dbo.T_Follow] PRIMARY KEY ([FollowerID], [LeaderID])
)
CREATE INDEX [IX_FollowerID] ON [dbo].[T_Follow]([FollowerID])
CREATE INDEX [IX_LeaderID] ON [dbo].[T_Follow]([LeaderID])
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_FollowerID] FOREIGN KEY ([FollowerID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE no ACTION;
ALTER TABLE [dbo].[T_Follow] ADD CONSTRAINT [FK_dbo.T_Follow_dbo.T_User_LeaderID] FOREIGN KEY ([LeaderID]) REFERENCES [dbo].[T_User] ([UserID]) ON DELETE no ACTION;


另外, 设置显式的外键, 其实在生产环境是大忌, 一般不要做这个事。只有学生才搞这个玩意。

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧