0

在两个不直接相关的表之间查询数据的最佳方法是什么,但通过第三个甚至第四个表,使用外键相关?

类似的东西1 -> 2 -> 3 -> 4

我看到了许多非常不同的建议,但想找出在这种情况下最好的方法是什么,我尝试维护关系数据库模型,同时避免超级复杂的 SQL 查询。

这是与我的情况相匹配的示例:

CREATE TABLE `user` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(50) DEFAULT NULL,
    `city_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_city_id` FOREIGN KEY (`city_id`) 
    REFERENCES `city` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
CREATE TABLE `city` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(50) DEFAULT NULL,
    `country_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_country_id` FOREIGN KEY (`country_id`) 
    REFERENCES `country` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
CREATE TABLE `country` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(50) DEFAULT NULL,
    `continent_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_continent_id` FOREIGN KEY (`continent_id`) 
    REFERENCES `continent` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
CREATE TABLE `continent` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;

假设我想从特定大陆获取所有用户

SELECT name FROM user WHERE city_id IN (
    SELECT id FROM city WHERE country_id IN (
        SELECT id FROM country WHERE continent_id = 1 ) ) );

我猜它看起来不错,但是如果我想从特定城市获取所有用户怎么办

SELECT name FROM user WHERE city_id IN (
  SELECT id FROM city WHERE country_id IN (
    SELECT id FROM country WHERE continent_id = (
      SELECT continent_id FROM country WHERE id = (
        SELECT country_id FROM city WHERE id = 1 ) ) ) );

这有效率吗?

也许用 JOIN 也能达到同样的效果?

我试图避免将所有值添加到用户表中,以维护该关系city->country->continent并涉及关系来完成这项工作,但也许在这种情况下它只是不值得这样做?..可能效率不高,重新设计数据库会更好吗?

4

2 回答 2

1

内连接

-- get users to cities
from
 City c
 inner join Users u
  on c.Id = u.City_Id

-- users to continents
from
 Users u
 inner join City ci
  on u.City_id = ci.Id
 inner join Country co
  on ci.Country_Id = co.Id
 inner join Continent con
  on co.Continent_Id = con.Id
于 2013-10-11T20:58:34.447 回答
1

应该是这样的,你可能想要分析(解释为什么 JOIN 比子查询更好)解释手册页http://dev.mysql.com/doc/refman/5.7/en/explain.html

请注意,您只能使用以下过滤器信任 INNER JOIN,使用 LEFT JOIN 或 RIGHT JOIN 可能会得到错误的结果。

对于一个大陆内的所有用户,continent_id = 1

SELECT
 user.name 

FROM
 user

INNER JOIN 
 city
ON
 user.city_id = city.id

INNER JOIN 
 country
ON
  city.country_id = country.id
 AND
  country.continent_id = 1
;

对于 city_id = 1 的城市内的所有用户

SELECT
 user.name 

FROM
 user

INNER JOIN 
 city
ON
  user.city_id = city.id
 AND
  city.id = 1

http://sqlfiddle.com/#!2/1c40e/23

于 2013-10-11T22:49:35.597 回答