MySQL中的错误1005(来自外键语法?)

时间:2013-11-23 00:35:48

标签: mysql sql foreign-keys

我在MySQL中创建以下表时遇到错误。

这是错误:

ERROR 1005 (HY000): Can't create table 'Works' (errno: 150)

你们可以看看Works()的外键吗?如果你看到任何会导致这个错误发生的奇怪事情,请告诉我吗?

这是我的整体架构:

create table Employee(
        Lastname    varchar(10),
        FirstName   varchar(10),
        MidInitial  char(1),
        gender      char(1),
        street      varchar(10),
        city        varchar(10),
        primary key(Lastname, FirstName, MidInitial));

create table company(
    company_name    varchar(20),
    city    varchar(10),
    primary key(company_name));

create table Works(
    Lastname    varchar(10),
    FirstName   varchar(10),
    MidInitial  char(1),
    company_name    varchar(20),
    salary      numeric(8,2),
    primary key(Lastname, FirstName, MidInitial, company_name),
    foreign key(Lastname, FirstName, MidInitial) references Employee,
    foreign key(company_name) references company);

非常感谢!

3 个答案:

答案 0 :(得分:3)

您的错误是由于错误的外键语法引起的。

但是,我认为你应该使用ID字段而不是字符串复合主键。您的方法存在一些问题......

  • 与使用整数(ID)字段加入(更难= =更多处理时间)相比,这会使DB更难连接表。

  • 即使使用中间名,也可以有多个同名的人。

  • 如果您需要更改某人的姓名,会发生什么?或者因为存储错误或者他们结婚或者其他事情......这意味着您将拥有不仅要更新您的employee表,还要更新works表和您将该名称用作外键的任何其他表。


看看这个: http://sqlfiddle.com/#!2/2dc8c/3/0

我已为每个表添加了表格ID 。这是一个unsigned int,这意味着它不能是负面的(因为这没有多大意义)。它也是auto_increment,这意味着每次向表中添加一行时,此ID将自动生成并上升1.

    create table Employee (
          Employee_ID int unsigned auto_increment primary key,

          Lastname    varchar(10),
          FirstName   varchar(10),
          MidInitial  char(1),

          gender      char(1),

          street      varchar(10),
          city        varchar(10),

          unique (Lastname, FirstName, MidInitial)
      );

你可以像这样添加这个表:

    insert into Employee (Employee_ID, LastName, FirstName, MidInitial) 
                   values (null,       'Smith',  'John',    'K');

null将成为自动生成的ID。它对于每一行都是唯一的。

此外,唯一约束表示这些字段的组合在表格中必须是唯一的。但是,如果有足够大的公司,我打赌两个人会有相同的名字。在现实生活中,我建议删除这个独特的约束。


我对公司表进行了类似的更改......

     create table company(
         company_ID      int unsigned auto_increment primary key,

         company_name    varchar(20),
         city            varchar(10),

         unique (company_name)
    );

可以添加如下内容:

     insert into company values (null, 'Taco Bell', 'Paris'); 

所以...对于works ....而不是在此表中一遍又一遍地存储每个人的全名和完整的公司名称,现在我们只需要存储ID'秒。

    create table Works (
         works_id      int unsigned auto_increment primary key,

         employee_id   int unsigned, 
         compay_id     int unsigned,  

         salary        numeric(8,2), 

         foreign key (employee_id) references Employee (employee_id), 
         foreign key (compay_id) references company (company_id) 
    );

您可以像这样添加works

    insert into Works values (null, 1, 1, '10.00');

由于John Smith是我们的第一个员工,他的Employee_ID将是1.要验证,请尝试select * from Employee where FirstName='John' and LastName='Smith'。 Taco Bell也会得到company_id = 1.通过将这些值插入works,这意味着John现在在Taco Bell工作。

我还建议您在工作表中添加start_dateend_date以及job_title等字段。而且你也想特别考虑这个表的任何独特约束。人们可以不止一次为同一家公司工作。他们也可以有不同的工作。


如果要恢复数据,可以使用如下查询:

  select FirstName, MidInitial, LastName, 
         Company_Name, 
         Salary 

  from   employee

         join works 
           on works.employee_id = employee.employee_id

         join company 
           on works.company_id = company.company_id 

这只是一种奇特的说法:

  select FirstName, MidInitial, LastName, 
         Company_Name, 
         Salary 

  from   employee, works, company

  where  employee.employee_id = works.employee_id and

         company.company_id = works.company_id  

关于数据库事物的一些注释......

  • 选择一个命名约定并坚持下去!如果您想使用CamelCase,请随处使用。如果you_want_to_use在您的名字中下划线,请在任何地方使用它们。有大量的命名约定可供选择:使用表名称为属性(列/字段)添加前缀,使用常用缩写(或不使用),使用(或不使用)大小写...这主要取决于个人偏好但有有关于使用某些的利弊的文章。最后一点,_因为你可以在名称中使用空格,__并不意味着你应该这样做。 `Almost all`数据库如果您愿意,可以在[you use spaces]中使用works,但以后可能会导致很多问题。

  • 表名不应该是复数。这是我的宠儿,这就是为什么:我们知道一张桌子会有很多记录......很多人/人员,许多员工,多家公司,任何类型或种类的多个条目。每行只描述一个这些东西。有时,将名称复数只是有意义。其他时候,这是有问题的 - 比如id表。如果你有时把它变成复数,有时会使它变得单数,那么以后就会变得混乱。通过简单地使它变得单一,它仍然是完全合理的,并且你不会来回切换或者在编写查询时必须查找确切的名称。

  • 数据类型非常重要并尝试在类似字段的表之间保持一致(与所有ID相同的类型; make all boolean fields所有位或整数或其他,只是使它们相同)。您可以选择不同大小的整数类型。考虑尺寸,性能以及适合您需求的内容。确定你是否真的需要nvarchar或varchar是否合适。

    • 日期永远不会存储为字符串。 使用适当的日期,日期时间,时间或时间戳数据类型。这将在以后需要检索,比较或在计算中使用时为您提供帮助。另一个重要决定是如何选择处理时区。当信息呈现给用户时,我喜欢以UTC格式存储所有内容并处理前端的任何时区偏移事物。这使得一切都保持一致,我不必担心根据用户的计算机时间,用户的浏览器时间,我的数据库时间,是否在下午6点插入行。或者服务器的时间
  • 包含对每个表中的行唯一的auto_increment字段。最简单的方法是使用identity(1,1)(mysql)或mysql_(sql server)字段,以便数据库为您跟踪它。如果需要,可以重置或重新设置这些值。

  • 学习使用normalization.

  • 了解transactions做了什么以及为什么它们很重要......即使您不使用它们。

  • 了解不同类型的联接This is one of the best explanations I have ever seen.要注意的主要事项是连接应该是外连接还是内连接。

  • 了解SQL Injection,更重要的是how to prevent it(该链接适用于PHP)。

  • 如果您使用的是PHP,请不要使用旧的PDO课程。相反,请使用MySQLi_NULLInfo...

  • 数据库最重要的是数据完整性,验证和清理。用户希望将各种草率,脏的数据放入表中。是密苏里州还是密苏里州?女,女,女,还是?工资是每小时15.00,每年50k,还是3,000薪水?是2013年12月31日,2013年12月31日,12月31日至13日,2013年12月31日或12月30日 - 二千一十三年?

  • 决定是否允许Middle_Initial 。由于三态逻辑,它会使事情变得更复杂,您需要稍后检查它。有些人决定只使用空字符串。 NULL 更多的是状态而不是实际值,它意味着未定义或未知 - 值可以是任何值。我使用 null ,因为空字符串有时是字段的有效值。例如,将{{1}}设置为等于空字符串可能意味着该人没有中间首字母,或者可能意味着您不知道它是什么。对我来说,这些事情是不同的。对其他人来说,差异并不重要。只考虑数字......与未知数相同吗?

  • 如果不出意外,请保持一致。

答案 1 :(得分:0)

主键列不能为NULL,需要将其设置为NOT NULL(不允许空值),类似这样的

create table Employee(
        Lastname    varchar(10) NOT NULL,
        FirstName   varchar(10) NOT NULL,
        MidInitial  char(1) NOT NULL,
        gender      char(1),
        street      varchar(10),
        city        varchar(10),
        primary key(Lastname, FirstName, MidInitial));

create table company(
    company_name    varchar(20) NOT NULL,
    city    varchar(10),
    primary key(company_name));

这将解决问题,但在varchar值上使用主键是一种不好的做法,我认为您应该在每个表中添加一个Identity列以用作主键,并在其他列上创建检查约束以强制您的业务规则。

答案 2 :(得分:0)

来自您的PRIMARY KEY的列为NULLABLE,您获得的错误与此无关,但是关于FOREIGN KEY上的多个列并且缺少原始表中引用的列。你应该这样做:

CREATE TABLE Works (
  Lastname VARCHAR(10) NOT NULL,
  FirstName VARCHAR(10) NOT NULL,
  MidInitial CHAR(1) NOT NULL,
  company_name VARCHAR(20) NOT NULL,
  salary NUMERIC(8, 2),
  PRIMARY KEY (Lastname,FirstName,MidInitial,company_name),
  CONSTRAINT fk_works FOREIGN KEY (Lastname,FirstName,MidInitial) 
      REFERENCES Employee(Lastname, FirstName, MidInitial),
  FOREIGN KEY (company_name) REFERENCES company(company_name)
  );