SQL连接表 - 它是完全需要主键还是仅需要唯一键?

Ben*_*ley 0 mysql sql cakephp

我已经为CakePHP框架创建了一个使用连接表的应用程序.

我不确定是否需要一个主键来uniquley标识连接表的每一行,如SQL的第一个块所示.

这两个字段是否需要设置为唯一键,还是可以将它们都设置为主键,我将id作为主键删除?

我还被问到为什么使用表约束而不是列约束来声明原子主键,这是否意味着我不应该为连接表设置唯一键?

CREATE TABLE IF NOT EXISTS `categories_invoices` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `category_id` int(11) NOT NULL,
  `invoice_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `category_id` (`category_id`,`invoice_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=163 ;
Run Code Online (Sandbox Code Playgroud)

我认为解决方案可能是将两个密钥设置为唯一,并删除主键,如下所示:

 CREATE TABLE IF NOT EXISTS `categories_invoices` (
      `category_id` int(11) NOT NULL,
      `invoice_id` int(11) NOT NULL,
      UNIQUE KEY `category_id` (`category_id`,`invoice_id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)

我确实测试了删除连接表的主键'id',只留下'category_id'和'invoice_id',应用程序仍然有用.这使得两个字段都作为连接表中的唯一字段.这实际上是正确的做法吗?

ype*_*eᵀᴹ 6

你不需要两者.复合唯一键可以替换主键(除非Cake框架不能处理复合Priamry键):

 CREATE TABLE IF NOT EXISTS categories_invoices (
      category_id int(11) NOT NULL,
      invoice_id int(11) NOT NULL,
      PRIMARY KEY (category_id, invoice_id)
    ) 
    ENGINE = MyISAM 
    DEFAULT CHARSET = latin1 ;
Run Code Online (Sandbox Code Playgroud)

除了为主键创建的索引之外,还有另一个索引,顺序相反:

   INDEX (invoice_id, category_id)
Run Code Online (Sandbox Code Playgroud)

如果要定义外键约束,则应使用InnoDB引擎.随着MyISAM你不能有外键.那么,它将是:

 CREATE TABLE IF NOT EXISTS categories_invoices (
      category_id int(11) NOT NULL,
      invoice_id int(11) NOT NULL,
      PRIMARY KEY (category_id, invoice_id),
      INDEX invoice_category_index (invoice_id, category_id)
    ) 
    ENGINE = InnoDB  
    DEFAULT CHARSET=latin1 ;
Run Code Online (Sandbox Code Playgroud)

如果Cake无法处理复合主键:

 CREATE TABLE IF NOT EXISTS categories_invoices (
      id int(11) NOT NULL AUTO_INCREMENT,
      category_id int(11) NOT NULL,
      invoice_id int(11) NOT NULL,
      PRIMARY KEY (id),
      UNIQUE KEY category_invoice_unique (category_id, invoice_id),
      INDEX invoice_category_index (invoice_id, category_id)
    ) 
    ENGINE = InnoDB  
    DEFAULT CHARSET=latin1 ;
Run Code Online (Sandbox Code Playgroud)