多个列上的MySQL外键?

多个列上的MySQL外键?,mysql,Mysql,我还在学习MySQL,所以请耐心等待 下面列出了几个表,我想记录这些表的错误消息。我指的不是查询错误,而是我的消息,比如连接到站点失败、站点xyz的读卡错误等等 我想用一个表error_logs来记录我的错误,只需三列: 身份证件 错误信息 你是活跃的吗 然而,我遇到的问题是,每个错误都与“cards”、“doors”或“sites”表中的一个记录有关,我希望跟踪消息所属的各个表中的哪个记录 所以,我的问题是,什么是解决这个问题的最佳方法?我考虑添加两个额外的列,“record_id”将引用另一

我还在学习MySQL,所以请耐心等待

下面列出了几个表,我想记录这些表的错误消息。我指的不是查询错误,而是我的消息,比如连接到站点失败、站点xyz的读卡错误等等

我想用一个表error_logs来记录我的错误,只需三列:

身份证件 错误信息 你是活跃的吗 然而,我遇到的问题是,每个错误都与“cards”、“doors”或“sites”表中的一个记录有关,我希望跟踪消息所属的各个表中的哪个记录

所以,我的问题是,什么是解决这个问题的最佳方法?我考虑添加两个额外的列,“record_id”将引用另一个表中的id,而“table”将跟踪消息所属的表。另外,另一个警告是,未来很可能会有更多的主表

以下是我迄今为止的表格:

CREATE TABLE `statuses` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1$$;

INSERT INTO statuses SET name = 'error';
INSERT INTO statuses SET name = 'pre-install';
INSERT INTO statuses SET name = 'validate';
INSERT INTO statuses SET name = 'active';
INSERT INTO statuses SET name = 'disabled';

CREATE TABLE `sites` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `status_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `sites_status_id_idx` (`status_id`),
  CONSTRAINT `sites_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$;

CREATE TABLE `doors` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `description` varchar(255) NOT NULL,
  `site_id` int(11) NOT NULL,
  `status_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `doors_site_id_idx` (`site_id`),
  KEY `doors_status_id_idx` (`status_id`),
  CONSTRAINT `doors_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE,
  CONSTRAINT `doors_site_id` FOREIGN KEY (`site_id`) REFERENCES `sites` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$;

CREATE TABLE `card_types` (
  `id` int(11) NOT NULL,
  `manufacturer` varchar(45) DEFAULT NULL,
  `sequance` varchar(32) DEFAULT NULL,
  `auth_code` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$;

CREATE TABLE `cards` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `number` int(11) NOT NULL,
  `type_id` int(11) NOT NULL,
  `status_id` int(11) NOT NULL,
  `is_oem` bit(1) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `number_UNIQUE` (`number`),
  KEY `cards_type_id_idx` (`type_id`),
  KEY `cards_status_id_idx` (`status_id`),
  CONSTRAINT `cards_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE,
  CONSTRAINT `cards_type_id` FOREIGN KEY (`type_id`) REFERENCES `card_types` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$;

CREATE TABLE `card_assignments` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `door_id` int(11) NOT NULL,
  `status_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `card_assignments_door_id_idx` (`door_id`),
  KEY `card_assignments_status_id_idx` (`status_id`),
  CONSTRAINT `card_assignments_door_id` FOREIGN KEY (`door_id`) REFERENCES `doors` (`id`) ON UPDATE CASCADE,
  CONSTRAINT `card_assignments_status_id` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$;

我认为你的建议完全正确。请确保选择一个枚举 表名称字段的数据类型;这样,不同的表名就可以 MySQL透明地映射到整数值。这将比VARCHAR字段使用更少的内存 选择与特定表相关的错误会更快。额外的 表名称上的索引/键 记录id将进一步提高性能。您可以按如下方式创建表:

CREATE TABLE IF NOT EXISTS `error_logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `table_name` enum('sites','tables','doors') CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
  `record_id` int(11) NOT NULL DEFAULT '0',
  `error_message` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
  `is_active` tinyint(4) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `table_name` (`table_name`,`record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
SELECT * FROM error_logs2 WHERE sites_id IS NOT NULL
按表名称选择错误非常简单,如下所示:

SELECT * FROM error_logs WHERE table_name = 'sites'
如前所述添加其他实体和表时,请记住适当扩展表名称枚举

我发现在您的情况下,另一种稍逊于您的方法是为每个主表使用单独的id字段:

CREATE TABLE IF NOT EXISTS `error_logs2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `cards_id` int(11) DEFAULT NULL,
  `doors_id` int(11) DEFAULT NULL,
  `sites_id` int(11) DEFAULT NULL,
  `error_message` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
  `is_active` tinyint(4) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `cards_id` (`cards_id`),
  KEY `doors_id` (`doors_id`),
  KEY `sites_id` (`sites_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
在这里,只有一个id字段包含一个值,另外两个字段为空。要插入与站点表和记录id 1相关的错误:

INSERT INTO `error_logs2` (`id`, `cards_id`, `doors_id`, `sites_id`, `error_message`, `is_active`)
VALUES (NULL, NULL, NULL, '1', 'Exception has occurred: Division by zero.', '1')
选择站点错误的工作方式如下:

CREATE TABLE IF NOT EXISTS `error_logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `table_name` enum('sites','tables','doors') CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
  `record_id` int(11) NOT NULL DEFAULT '0',
  `error_message` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
  `is_active` tinyint(4) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `table_name` (`table_name`,`record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
SELECT * FROM error_logs2 WHERE sites_id IS NOT NULL
但是,要将错误关联到新实体,您必须向error_logs2表中添加一个新列。但是,为一个特定实体和id选择错误只需要一个字段比较,例如:

SELECT * FROM error_logs2 WHERE cards_id = 5

马塞勒斯,非常感谢你的意见!我将利用您最初的建议创建表,正如您在表列的enum数据类型中概述的那样。谢谢