1

我有以下数据结构和数据:

CREATE TABLE `parent` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(10) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `parent` VALUES(1, 'parent 1');
INSERT INTO `parent` VALUES(2, 'parent 2');

CREATE TABLE `other` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(10) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `other` VALUES(1, 'other 1');
INSERT INTO `other` VALUES(2, 'other 2');

CREATE TABLE `relationship` (
  `id` int(11) NOT NULL auto_increment,
  `parent_id` int(11) NOT NULL,
  `other_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `relationship` VALUES(1, 1, 1);
INSERT INTO `relationship` VALUES(2, 1, 2);
INSERT INTO `relationship` VALUES(3, 2, 1);

我想找到其他 1 和 2 的父记录。

这是我想出来的,但我想知道是否有更好的方法:

SELECT p.id, p.name
FROM parent AS p
    LEFT JOIN relationship AS r1 ON (r1.parent_id = p.id)
    LEFT JOIN relationship AS r2 ON (r2.parent_id = p.id)
WHERE r1.other_id = 1 AND r2.other_id = 2;

结果是 1,“父 1”是正确的。问题是,一旦你得到一个超过 5 个连接的列表,它就会变得混乱,并且随着关系表的增长,它会变得很慢。

有没有更好的办法?

我正在使用 MySQL 和 PHP,但这可能非常通用。

4

7 回答 7

4
于 2009-03-01T08:08:27.360 回答
2

鉴于父表在 (parent_id, other_id) 上包含唯一键,您可以这样做:

select p.id, p.name 
  from parent as p 
 where (select count(*) 
        from relationship as r 
       where r.parent_id = p.id 
         and r.other_id in (1,2)
        ) >= 2
于 2009-03-01T08:16:02.893 回答
1

稍微简化一下,这应该有效且有效。

SELECT DISTINCT p.id, p.name
FROM parent p
INNER JOIN 关系 r1 ON p.id = r1.parent_id AND r1.other_id = 1
INNER JOIN 关系 r2 ON p.id = r2.parent_id AND r2.other_id = 2

对于每个“其他”值,将需要至少一个连接记录。优化器应该知道它只需要找到一个匹配项,它只需要读取索引,而不是任何一个子表,其中一个甚至根本没有被引用。

于 2009-03-01T08:28:21.617 回答
0

我还没有实际测试过它,但大致如下:

SELECT id, name FROM (
  SELECT p1.id, p1.name
  FROM parent AS p1 LEFT JOIN relationship as r1 ON(r1.parent_id=p1.id)
  WHERE r1.other_id = 1
  UNION ALL
  SELECT p2.id, p2.name
  FROM parent AS p2 LEFT JOIN relationship as r2 ON(r2.parent_id=p2.id)
  WHERE r2.other_id = 2
   -- etc
) GROUP BY id, name
HAVING count(*) = 2

这个想法是您不必进行多路连接;只需连接常规连接的结果,按您的 id 分组,然后选择出现在每个段中的行。

于 2009-03-01T08:12:52.527 回答
0
于 2009-03-01T08:17:39.693 回答
0

您可以使用嵌套 select 来完成,我在 MSSQL 2005 中对其进行了测试,但正如您所说,它应该非常通用

SELECT * FROM parent p
WHERE p.id in(
    SELECT r.parent_Id 
    FROM relationship r 
    WHERE r.parent_id in(1,2) 
    GROUP BY r.parent_id
    HAVING COUNT(r.parent_Id)=2
)

并且数字 2COUNT(r.parent_Id)=2是根据您需要的连接数)

于 2009-03-01T08:27:39.293 回答
0

如果您可以将您的 other_id 值列表放入一个理想的表中。下面的代码查找至少具有给定 ID 的父母。如果您希望它具有完全相同的 id(即没有额外内容),则必须稍微更改查询。

SELECT
     p.id,
     p.name
FROM
     My_Other_IDs MOI
INNER JOIN Relationships R ON
     R.other_id = MOI.other_id
INNER JOIN Parents P ON
     P.parent_id = R.parent_id
GROUP BY
     p.parent_id,
     p.name
HAVING
     COUNT(*) = (SELECT COUNT(*) FROM My_Other_IDs)
于 2009-03-01T16:18:43.950 回答