MySQL фильтр запрос с отношением - PullRequest
1 голос
/ 27 июля 2010

У меня следующая проблема с двумя таблицами MySQL, которые имеют отношение: Я легко могу запросить таблицу 1 (адрес), когда мне нужен полный список, или отфильтровать результат по имени, электронной почте или тому подобное. Но теперь мне нужно запросить таблицу 1 и отфильтровать ее на основе реляционного содержимого таблицы 2 (интересы). Поэтому мне нужно найти строку (обычно много строк) в таблице 1, только если (или более) условия выполнены в таблице 2.

Вот таблицы:

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, так и cat = aa и subcat = yy. Особенно важно последнее, и нужно иметь в виду, что и таблицы адресов, и таблицы интересов будут длинными списками и что количество комбинаций кошка / подкадр будет различным. В настоящее время я работаю со справочными запросами через Zend_Db_Table (findDependentRowset), но это решение является способом замедления для списков адресов, насчитывающих 100 и даже 1000 обращений.

Спасибо за вашу помощь.

Ответы [ 2 ]

2 голосов
/ 27 июля 2010
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 голос
/ 27 июля 2010

Я добавил еще одну строку в вашу таблицу интересов, чтобы продемонстрировать различный набор результатов между двумя примерами:

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)

Использовать коррелированные подзапросы легко и просто. Однако имейте в виду, что он может быть не лучшим с точки зрения производительности, поскольку коррелированные подзапросы будут выполняться один раз для каждого адреса во внешнем запросе.

...