1

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

我不确定是否需要一个主键来唯一标识连接表的每一行,如 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 ;

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

 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;

事实上,我确实测试过删除连接表的主键“id”,只留下“category_id”和“invoice_id”,应用程序仍然有效。这使这两个字段都成为连接表中的唯一字段。这实际上是正确的做法吗?

4

2 回答 2

6

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

 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 ;

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

   INDEX (invoice_id, category_id)

如果你想定义外键约束,你应该使用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 ;

如果 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 ;
于 2012-05-05T13:12:39.690 回答
2

第二种方法没有任何问题。它被称为复合键,在数据库设计中非常常见,尤其是在您的情况下。

http://en.wikipedia.org/wiki/Relational_database#Primary_keys

于 2012-05-05T13:15:42.007 回答