2010-07-27 113 views
1

我有两个有关系的MySQL表有以下问题: 当我想要一个完整列表或按名称或电子邮件等过滤结果时,我可以轻松查询表1(地址) 。但是现在我需要查询表1并根据表2(兴趣)的关系内容对其进行过滤。所以,我需要找到在表1的行(通常是多行)仅在(或更多)的条件在表2中与关系的MySQL过滤器查询

在这里会见是表:

CREATE TABLE IF NOT EXISTS `address` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL, 
    `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL, 
    `countryCode` char(2) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `languageCode` char(2) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `emailUnique` (`email`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

INSERT INTO `address` (`id`, `name`, `email`, `countryCode`, `languageCode`, `timestamp`) VALUES 
(1, '', '[email protected]', 'BE', 'nl', '2010-07-16 14:07:00'), 
(2, '', '[email protected]', 'BE', 'fr', '2010-07-16 14:10:25'); 

CREATE TABLE IF NOT EXISTS `interests` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `address_id` int(11) unsigned NOT NULL, 
    `cat` char(2) COLLATE utf8_unicode_ci NOT NULL, 
    `subcat` char(2) COLLATE utf8_unicode_ci NOT NULL, 
    `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (`id`), 
    KEY `address_id` (`address_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

INSERT INTO `interests` (`id`, `address_id`, `cat`, `subcat`, `timestamp`) VALUES 
(1, 1, 'aa', 'xx', '2010-07-16 14:07:00'), 
(2, 1, 'aa', 'yy', '2010-07-16 14:07:00'), 
(3, 2, 'aa', 'xx', '2010-07-16 14:07:00'), 
(4, 2, 'bb', 'zz', '2010-07-16 14:07:00') 
(5, 2, 'aa', 'yy', '2010-07-16 14:07:00'); 

ALTER TABLE `interests` 
    ADD CONSTRAINT `interests_ibfk_1` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION; 

例如,我需要找到(有)作为兴趣cat = aa和subcat = xx的地址。或者,另一个例子,我需要的地址(猫)同时感兴趣cat = aa和subcat = xx AND cat = aa和subcat = yy。特别是后者是重要的,必须记住地址和兴趣表将是长列表,并且猫/子猫组合的数量将会变化。我现在正在通过Zend_Db_Table(findDependentRowset)处理参考查询,但是解决方法是减慢地址列表的编号,数字为100甚至1000。

谢谢你的帮助。

回答

1

我又增加了一行在您的利益表格,演示不同的结果这两个例子之间设置:

INSERT INTO interests VALUES (6, 2, 'aa', 'vv', '2010-07-16 14:07:00'); 

那么你可能想使用相关子查询如下尝试:

SELECT * 
FROM address a 
WHERE EXISTS (SELECT id 
       FROM interests 
       WHERE address_id = a.id AND 
         (cat = 'aa' and subcat = 'xx')); 

结果:

+----+------+--------------------+-------------+--------------+---------------------+ 
| id | name | email    | countryCode | languageCode | timestamp   | 
+----+------+--------------------+-------------+--------------+---------------------+ 
| 1 |  | [email protected]  | BE   | nl   | 2010-07-16 14:07:00 | 
| 2 |  | [email protected] | BE   | fr   | 2010-07-16 14:10:25 | 
+----+------+--------------------+-------------+--------------+---------------------+ 
2 rows in set (0.00 sec) 

对于第二个例子,我们正在测试的新行先前添加的,为了不具有相同的结果如上:

SELECT * 
FROM address a 
WHERE EXISTS (SELECT id 
       FROM interests 
       WHERE address_id = a.id AND 
         (cat = 'aa' and subcat = 'xx')) AND 
     EXISTS (SELECT id 
       FROM interests 
       WHERE address_id = a.id AND 
         (cat = 'aa' and subcat = 'vv')); 

结果:

+----+------+--------------------+-------------+--------------+---------------------+ 
| id | name | email    | countryCode | languageCode | timestamp   | 
+----+------+--------------------+-------------+--------------+---------------------+ 
| 2 |  | [email protected] | BE   | fr   | 2010-07-16 14:10:25 | 
+----+------+--------------------+-------------+--------------+---------------------+ 
1 row in set (0.00 sec) 

使用相关子查询是很简单的直截了当。但请记住,它在性能方面可能不是最好的,因为相关子查询将针对外部查询中的每个地址执行一次。

+0

欢迎您的精心解答。从某种意义上说,这正是Zend所做的。对于每个地址,检查是否通过findDependentRowset满足条件。但是这些表格太大了,或者更好地说,查询总数需要很长时间。 – Peter 2010-07-27 07:36:33

+0

更正,这比findDependentRowset快得多。我已经运行了一些测试,都使用AND和OR结构,并且他们显示出相当可行的性能,至少在我目前的开发数据库中。我现在正在开会,但稍后会进一步测试。这可能是我的解决方案。 – Peter 2010-07-27 08:12:18

2
SELECT a.name FROM address a 
INNER JOIN interests i ON (a.id = i.address_id) 
WHERE i.cat = "aa" AND i.subcat IN ('xx', 'yy') 
+0

整洁而快速,谢谢!如果我看到这个权利,这将导致所有具有aa/xx或aa/yy组合的地址。但是如果我想要aa/xx和aa/yy的那个呢? 如何去扔另一只猫在混合?这是正确的方式: SELECT a.name FROM address a INNER JOIN interests on ON(a.id = i.address_id) WHERE(i.cat =“aa”AND i.subcat IN('xx', 'yy')) OR(i.cat =“bb”AND i.subcat IN('zz','ww')) – Peter 2010-07-27 07:42:55