简体   繁体   中英

Is it ok to create more than one path to join tables?

Let's say I have a users table:

CREATE TABLE `users` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `city_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `users_city_id_foreign` (`city_id`),
  CONSTRAINT `users_city_id_foreign` FOREIGN KEY (`city_id`) REFERENCES `cities` (`id`)
);

That is linked to a cities table:

CREATE TABLE `cities` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `country_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `cities_country_id_foreign` (`country_id`),
  CONSTRAINT `cities_country_id_foreign` FOREIGN KEY (`country_id`) REFERENCES `countries` (`id`)
);

and that is linked to a countries table:

CREATE TABLE `countries` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
);

I'll often need the user's country name. I already have access to the country name via user->city->country :

SELECT `users`.`name`, `countries`.`name`
FROM `users` JOIN 
    (`cities` JOIN `countries` ON `cities`.`country_id` = `countries`.`id`)
    ON `users`.`city_id` = `cities`.`id`;

but I would like to have direct access like:

SELECT `users`.`name`, `countries`.`name`
FROM `users` JOIN `countries` ON `users`.`country_id` = `countries`.`id

Is it ok to add a foreign key linking directly the user table to the country table like this or should i avoid it?

ALTER TABLE `users` 
ADD COLUMN `country_id` BIGINT(20) UNSIGNED NOT NULL AFTER `city_id`,
ADD INDEX `users_country_id_foreign_idx` (`country_id` ASC);

ALTER TABLE `users` 
ADD CONSTRAINT `users_country_id_foreign`
  FOREIGN KEY (`country_id`)
  REFERENCES `countries` (`id`)
  ON DELETE NO ACTION
  ON UPDATE NO ACTION;

You create a risk of a data anomaly by adding the country_id to the users table. How would you explain this data:

countries:
 1, UK
 2, US

cities:
 1, Little Whinging, 1
 2, New York, 2

users:
 1, Harry Potter, 1, 2

How can Harry Potter live in a city in the UK, but be assigned a country_id corresponding to the US? That's an anomaly that is possible if you store the redundant country_id in the users table. You can make data that disagrees with itself.

You could solve this by making the pair of city_id and country_id in users reference the pair of city_id and country_id in the cities table. At least that would prevent the anomaly, because it would have to reference a key in that table in which that pair of values exists (you'd have to create a two-column key in cities first). But it's still redundant.

CREATE TABLE `users` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `city_id` bigint(20) unsigned NOT NULL,
  `country_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `users_city_country_foreign` FOREIGN KEY (`city_id`, `country_id`)
    REFERENCES `cities` (`id`, `country_id`)
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM