【问题标题】:Multiple columns from different tables as foreign keys to one column来自不同表的多列作为一列的外键
【发布时间】:2012-08-07 06:23:05
【问题描述】:

我对将多列作为单列的外键存有疑问。让我用一个例子来解释。

例如:我有 3 张桌子:

公司1Company_ID(guid) as Primary key, Address (varchar(25))

公司2Company_ID(guid) as Primary key, Address (varchar(25))

员工Employee_ID(guid) as Primary key, Company_ID ( Foreign key referencing from Company1 and Company2)

这里 Employee 表中 Company_ID 的外键来自 2 个不同的表。 这适用于 SQL Server 2008。

我的问题是我觉得这不正确。我从来没有在任何系统中这样做过,但我在一个示例中尝试过它并且它有效。我无法解释自己这里出了点问题,因为它运行良好。

我的假设是正确的还是请指导我?上述关系有什么缺陷?

USE [master]
GO
/****** Object:  Database [Test]    Script Date: 08/07/2012 14:32:32 ******/
CREATE DATABASE [Test] ON  PRIMARY 
( NAME = N'Test', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.FLEXIQUOTE\MSSQL\DATA\Test.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
 LOG ON 
( NAME = N'Test_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.FLEXIQUOTE\MSSQL\DATA\Test_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO
ALTER DATABASE [Test] SET COMPATIBILITY_LEVEL = 100
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [Test].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [Test] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [Test] SET ANSI_NULLS OFF
GO
ALTER DATABASE [Test] SET ANSI_PADDING OFF
GO
ALTER DATABASE [Test] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [Test] SET ARITHABORT OFF
GO
ALTER DATABASE [Test] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [Test] SET AUTO_CREATE_STATISTICS ON
GO
ALTER DATABASE [Test] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [Test] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [Test] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [Test] SET CURSOR_DEFAULT  GLOBAL
GO
ALTER DATABASE [Test] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [Test] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [Test] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [Test] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [Test] SET  DISABLE_BROKER
GO
ALTER DATABASE [Test] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [Test] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [Test] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [Test] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [Test] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [Test] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [Test] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [Test] SET  READ_WRITE
GO
ALTER DATABASE [Test] SET RECOVERY SIMPLE
GO
ALTER DATABASE [Test] SET  MULTI_USER
GO
ALTER DATABASE [Test] SET PAGE_VERIFY CHECKSUM
GO
ALTER DATABASE [Test] SET DB_CHAINING OFF
GO
USE [Test]
GO
/****** Object:  Table [dbo].[Table2]    Script Date: 08/07/2012 14:32:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table2](
    [Company2ID] [int] NOT NULL,
    [COmpanyAddress] [nchar](10) NULL,
 CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED 
(
    [Company2ID] 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
/****** Object:  Table [dbo].[Table1]    Script Date: 08/07/2012 14:32:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table1](
    [Company1ID] [int] NOT NULL,
    [CompanyName] [nchar](10) NULL,
 CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED 
(
    [Company1ID] 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
/****** Object:  Table [dbo].[Table3]    Script Date: 08/07/2012 14:32:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table3](
    [EMployeeID] [int] NOT NULL,
    [Company] [int] NULL,
 CONSTRAINT [PK_Table3] 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
/****** Object:  ForeignKey [FK_Table3_Table1]    Script Date: 08/07/2012 14:32:32 ******/
ALTER TABLE [dbo].[Table3]  WITH CHECK ADD  CONSTRAINT [FK_Table3_Table1] FOREIGN KEY([Company])
REFERENCES [dbo].[Table1] ([Company1ID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Table3] CHECK CONSTRAINT [FK_Table3_Table1]
GO
/****** Object:  ForeignKey [FK_Table3_Table2]    Script Date: 08/07/2012 14:32:32 ******/
ALTER TABLE [dbo].[Table3]  WITH CHECK ADD  CONSTRAINT [FK_Table3_Table2] FOREIGN KEY([Company])
REFERENCES [dbo].[Table2] ([Company2ID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Table3] CHECK CONSTRAINT [FK_Table3_Table2]
GO

【问题讨论】:

  • 嗯,第一个问题是为什么要 2 个公司表?
  • 我给出了这个简单的例子,因为我无法向你解释真实的场景。也就是说,在某些遗留系统中有 2 个这样的表,我现在无法更改:)
  • 您说外键在 SQL Server 2008 中“工作” - 但我敢打赌,您实际上并没有在数据库中声明外键约束。
  • 那些不是guids,因为大多数人会理解这个词,他们是ints。一旦你开始插入数据,这个方案就会崩溃,除非你没有告诉我们在两个 Company 表中总会有任何特定 ID 的行。

标签: sql-server database foreign-keys primary-key guid


【解决方案1】:

你的感觉是对的。 . .这不是“正确的”。或者,至少,这是一个糟糕的设计决策。

但是,您的外键关系可能是复合键。通常,您将有另一列指定此引用的表。复杂之处在于这可能是一个“隐式”列。因此,如果一个表具有美国地址而另一个具有非美国地址,则这两个表都可能没有“IsUS”标志。但是,美国记录将引用一个表,而非美国记录将引用另一个表。

另一个问题是如何维护这些密钥。您真的不希望有两个具有相互依赖的主键的表。解决此问题的典型方法是将两张表合二为一。

虽然这是一个坏主意,但您可能不得不接受这种结构。如果你能改变它,你应该。

【讨论】:

    猜你喜欢
    • 2017-03-03
    • 2020-07-24
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    相关资源
    最近更新 更多