【问题标题】:What is the best way to query data between two tables which is not directly related在不直接相关的两个表之间查询数据的最佳方法是什么
【发布时间】:2013-10-11 20:52:00
【问题描述】:

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

类似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 并涉及关系来完成这项工作,但也许在这种情况下它只是不值得这样做? ..可能效率不高,最好重新设计数据库?

【问题讨论】:

  • IN 语句不好......当索引到位时,JOIN 更好......
  • 可以将您的表格和示例数据放在 SQLfriddle 上吗? sqlfiddle.com 那我给你看一些 JOIN 例子
  • 这里 sqlfiddle.com/#!2/1c40e/1 是 SQLFiddle.com 上的工作示例,感谢分享链接

标签: mysql sql database-design relational-database


【解决方案1】:

应该是这样的,您可能想要分析(解释为什么 JOIN 比子查询更好)EXPLAIN 手册页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

【讨论】:

    【解决方案2】:

    内部连接

    -- 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
    

    【讨论】:

      猜你喜欢
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-25
      • 2017-11-04
      • 1970-01-01
      • 2010-10-19
      相关资源
      最近更新 更多