如何有效且安全地将带有外键的记录插入数据库,并将其插入SQL Server?

时间:2018-11-04 18:49:06

标签: sql sql-server key

我正在SQL Server中编写数据库,我有这个schema

基于此,我已经准备好UML diagram

我已经编写了SQL代码来创建表并使用外键对其进行修改

CREATE TABLE Employee
(
    Fname VARCHAR(20),
    Minit CHAR(1),
    Lname VARCHAR(30),
    Ssn VARCHAR(9) CONSTRAINT pk_Employee PRIMARY KEY, -- pk key
    Bdate DATE,
    Address VARCHAR(30),
    Sex CHAR(1),
    Salary INT,
    Super_ssn VARCHAR(9),
    Dno INT,
    CONSTRAINT chk_Employee_Ssn CHECK (LEN(Ssn)=9)
);

CREATE TABLE Department
(
    Dname VARCHAR(30),
    Dnumber INT CONSTRAINT pk_Department PRIMARY KEY, -- pk key
    Mgr_ssn VARCHAR(9),
    Mgr_start_date DATE,
    CONSTRAINT chk_Department_MgrSsn CHECK (LEN(Mgr_ssn)=9)
);

CREATE TABLE Dept_locations
(
    Dnumber INT,
    Dlocation VARCHAR(30),
    CONSTRAINT pk_Dept_locations PRIMARY KEY (Dnumber,Dlocation) -- pk key
);

CREATE TABLE Project
(
    Pname VARCHAR(20),
    Pnumber INT CONSTRAINT pk_Project PRIMARY KEY, -- pk key
    Plocation VARCHAR(30),
    Dnum INT
);

CREATE TABLE Works_on
(
    Essn VARCHAR(9),
    Pno INT,
    Hours DECIMAL(7,2),
    CONSTRAINT pk_WorksOn PRIMARY KEY (Essn,Pno),   -- pk key
    CONSTRAINT chk_WorksOn_Essn CHECK (LEN(Essn)=9)
);

CREATE TABLE Dependent
(
    Essn VARCHAR(9) ,
    Dependent_name VARCHAR(20),
    Sex CHAR(1),
    Bdate DATE,
    Relationship VARCHAR(15),
    CONSTRAINT pk_Dependent PRIMARY KEY (Essn,Dependent_name), -- pk key
    CONSTRAINT chk_Dependent_Essn CHECK (LEN(Essn)=9)
);

ALTER TABLE Dependent ADD
    CONSTRAINT fk_Dependent_Essn FOREIGN KEY (Essn) REFERENCES Employee(Ssn)

ALTER TABLE Department ADD
    CONSTRAINT fk_Department_MgrSsn FOREIGN KEY (Mgr_ssn) REFERENCES Employee(Ssn)

ALTER TABLE Employee ADD
    CONSTRAINT fk_Employee_SuperSsn FOREIGN KEY (Super_ssn) REFERENCES Employee(Ssn),
    CONSTRAINT fk_Employee_Dno FOREIGN KEY (Dno) REFERENCES Department(Dnumber)

ALTER TABLE Dept_locations ADD
    CONSTRAINT fk_DeptLocations_MgrSsn FOREIGN KEY (Dnumber) REFERENCES Department(Dnumber)

ALTER TABLE Project ADD
    CONSTRAINT fk_Project  FOREIGN KEY (Dnum) REFERENCES Department(Dnumber)

ALTER TABLE Works_on ADD
    CONSTRAINT fk_WorksOn_Essn  FOREIGN KEY (Essn) REFERENCES Employee(ssn),
    CONSTRAINT fk_WorksOn_Pno  FOREIGN KEY (Pno) REFERENCES Project(Pnumber)

现在,当我尝试向这些表中插入一些数据时,

示例:

INSERT INTO Employee(Fname, Minit, Lname, SSn, Bdate, Address, Sex, Salary, Super_ssn, Dno) 
VALUES ('John', 'B', 'Smith', '123456789', '1965-01-09', 'Lazy Town', 'M', 30000, '333445555', 5);

我意识到大多数这些表都需要其他任何表的外键,这使得插入非常奇怪。要插入某些内容,我必须在数据库中已经有其他数据。就像是恶性循环。

我的问题:是否有任何方法可以有效,安全地插入记录,而不会因不存在的记录而导致错误?

编辑: 我试图使用那些表述(一个接一个,而不是一次全部)为这些表中的任何表插入一些数据。每次失败,因为外键无法在其他表中找到记录:<< / p>

INSERT INTO Employee(Fname,Minit,Lname,SSn,Bdate,Address,Sex,Salary,Super_ssn,Dno) VALUES
('John','B','Smith','123456789', '1965-01-09', 'Lazy Town', 'M', 30000, '333445555',5);

INSERT INTO Dept_locations(Dnumber,Dlocation) VALUES
    (1, 'Houston');

INSERT INTO Department(Dname,Dnumber,Mgr_ssn,Mgr_start_date) VALUES
    ('Research', 5, '333445555', '1988-05-22');

INSERT INTO Dependent(Essn,Dependent_name,Sex,Bdate,Relationship) VALUES
    ('333445555', 'Alice', 'F', '1986-04-05', 'Daughter');

INSERT INTO Works_on(Essn,Pno,Hours) VALUES
    ('333445555', 3, 10);

INSERT INTO PROJECT(Pname,Pnumber,Plocation,Dnum) VALUES
    ('ProductX', 1, 'Bellaire', 5);

4 个答案:

答案 0 :(得分:2)

外键用于数据一致性。这些键定义表之间的关系,您可以将关系视为一个链。因此,为了将数据添加到结构中,请从链的开头开始。例如,首先添加部门,然后将员工添加到部门中。如果不遵循该链,则无法使用外键将数据插入任何链接表中。

除非

如果您拖放前键,则可以进行插入。不过要小心!您可以将员工添加到不存在的部门中。

编辑:

fk_Department_MgrSsnfk_Employee_Dno是循环引用。您必须删除其中的一个,可能是fk_Department_MgrSsn,然后将一个列添加到Employee表中,并命名为“ isManager” ,以携带管理者信息。

答案 1 :(得分:1)

我同意@MertGülsoy,但是,我需要注意一些事情,

您的架构有3个主要的PK(Employee.SSN,Department.Dnumber,Project.Pnumber)。从这三个PK中,您将具有链接到它们的多个关系。

在SQL Server中,最简单的分配方法是先创建表,然后插入数据,然后创建关系,SQL Server还将检查现有数据中的外键。

让我们看一下外键Employee表(以了解关系):

员工表

  • [PK] SSN
  • [FK] Super_ssn
  • [FK] Dno

每个员工应具有唯一的SSN,但可以共享相同的Super_ssn。我认为Super_ssn打算成为Supervisor SSN。因此,在这种情况下,主管也需要在员工中有记录,以便与他建立联系。因此,您在Super_ssn中使用的每个Supervisor SSN也必须存在于SSN中(单独的记录)。在Dno上也是如此,这与Department表PK有关。每个Dno也必须存在于Department.Dnumber中。

因此,在插入雇员时要做的技巧是先插入主管记录,然后再插入与该主管记录相关的每个雇员。

例如:

INSERT INTO Employee(Fname,Minit,Lname,SSn,Bdate,Address,Sex,Salary,Super_ssn,Dno) VALUES
('John','B','Smith','123456789', '1965-01-09', 'Lazy Town', 'M', 30000, '333445555',NULL);

John的主管SSN不存在,那些关系将导致错误,要解决此问题,您需要先插入主管,然后再插入John,如下所示:

INSERT INTO Employee(Fname,Minit,Lname,SSn,Bdate,Address,Sex,Salary,Super_ssn,Dno) VALUES
('Mike','A','Tyson','333445555', '1965-01-09', 'Lazy Town', 'M', 50000, NULL,NULL),
('John','B','Smith','123456789', '1965-01-09', 'Lazy Town', 'M', 30000, '333445555',NULL);

迈克的Super_ssn值为NULL,因为没有与迈克相关的主管(他是老板)。

因此,现在您的Super_ssn链接正确了,因为333445555存在于SSN上,提示迈克的SSN。

请注意,我们给Dno NULL是因为我们还没有创建Department表。

您将对其余表执行相同的操作,只需确保每个外键都存在于主PK上即可。至于您当前的INSERT数据,其中有些则难以理解。

答案 2 :(得分:0)

外键在那儿。如果您希望能够插入无效数据,那么为什么根本需要外键?只需删除它们:)

但是,外键具有状态-它们是否可信任。如果要禁用外键,可以这样:

ALTER TABLE MY_TABLE NOCHECK CONSTRAINT FK_MY_TABLE_SOME_COLUMN

您还可以对表中的所有外键执行此操作:

ALTER TABLE MY_TABLE NOCHECK CONSTRAINT ALL

这将保留外键,因此您可以找出此列指向的位置,但是数据不会得到验证,并且您可以插入缺少值的行。

准备好重新启用外键时(如果需要),您可以这样操作:

ALTER TABLE MY_TABLE CHECK CONSTRAINT FK_MY_TABLE_SOME_COLUMN

请注意,如果存在无效数据行,此命令可能会失败。

关于效率,插入数据最有效的方法通常是BULK INSERT。如果未指定CHECK_CONSTRAINTS,则在插入数据时它不会服从您的外键,因此将使它们不受信任。但是,在您的示例中,您使用的是简单的插入语句,因此我想您不会寻找立即插入数百万行的方法。在这种情况下,外键不应影响您的插入效率(除非给数据一致性带来不便)。

答案 3 :(得分:0)

查看是否从UI或网页级别填充了数据,然后像这样简单地设计页面,

例如,在EmployeeSSNDNO中插入记录都会被下拉,因此没有垃圾数据的问题。

假设从其他来源插入了数据,则可以创建Instead of Trigger

如果批量插入,则可以使用Exists子句仅插入那些FK值存在的记录。

其他处理方式是使用TRY-CATCH。 因此,根据情况,您可以使用其中任何一种。

请勿禁用FK relation