MySQL过滤查询与关系

时间:2010-07-27 07:13:21

标签: mysql filter relational

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

以下是表格:

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, '', 'dummy@test.com', 'BE', 'nl', '2010-07-16 14:07:00'),
(2, '', 'test@somewhere.com', '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。特别是后者很重要,必须记住,地址和兴趣表都是长列表,cat / subcat组合的数量会有所不同。我目前正在通过Zend_Db_Table(findDependentRowset)处理参考查询,但该解决方案可以减慢编号为100s甚至1000次的地址列表。

感谢您的帮助。

2 个答案:

答案 0 :(得分: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')

答案 1 :(得分: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 |      | dummy@test.com     | BE          | nl           | 2010-07-16 14:07:00 |
|  2 |      | test@somewhere.com | 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 |      | test@somewhere.com | BE          | fr           | 2010-07-16 14:10:25 |
+----+------+--------------------+-------------+--------------+---------------------+
1 row in set (0.00 sec)

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