У меня есть таблица, полная предметов из разных источников. Некоторые из источников могут иметь одинаковое местоположение (в моем примере разные новостные каналы BBC будут разными, но все они исходят от BBC). Каждый элемент имеет «уникальный» идентификатор, который можно использовать для его идентификации среди других людей из того же места. Это означает, что элементы, относящиеся к одной и той же новости на сайте, но опубликованные в разных каналах, будут иметь один и тот же «уникальный идентификатор», но это не обязательно будет глобально уникальный.
Проблема заключается в том, что я хочу исключить дубликаты во время отображения, чтобы (в зависимости от того, какие каналы вы просматриваете) вы получали не более одной версии каждой истории, даже если два или три ваших канала могут содержать ссылки на это.
У меня есть таблица sources
с информацией о каждом источнике и полями location_id
и location_precedence
. Затем у меня есть таблица items
, содержащая каждый элемент, его unique_id
, source_id
и content
. Предметы с одинаковым unique_id
и источником location_id
должны появляться не более одного раза, а самый высокий источник location_precedence
выигрывает.
Я бы подумал, что-то вроде:
SELECT `sources`.`name` AS `source`,
`items`.`content`,
`items`.`published`
FROM `items` INNER JOIN `sources`
ON `items`.`source_id` = `sources`.`id` AND `sources`.`active` = 1
GROUP BY `items`.`unique_id`, `sources`.`location_id`
ORDER BY `sources`.`location_priority` DESC
сделает свое дело, но это, кажется, игнорирует поле приоритета местоположения. Что я пропустил?
Пример данных:
CREATE TABLE IF NOT EXISTS `sources` (
`id` int(10) unsigned NOT NULL auto_increment,
`location_id` int(10) unsigned NOT NULL,
`location_priority` int(11) NOT NULL,
`active` tinyint(1) unsigned NOT NULL default '1',
`name` varchar(150) NOT NULL,
`url` text NOT NULL,
PRIMARY KEY (`id`),
KEY `active` (`active`)
);
INSERT INTO `sources` (`id`, `location_id`, `location_priority`, `active`, `name`, `url`) VALUES
(1, 1, 25, 1, 'BBC News Front Page', 'http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml'),
(2, 1, 10, 1, 'BBC News England', 'http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/england/rss.xml'),
(3, 1, 15, 1, 'BBC Technology News', 'http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/technology/rss.xml'),
(4, 2, 0, 1, 'Slashdot', 'http://rss.slashdot.org/Slashdot/slashdot'),
(5, 3, 0, 1, 'The Daily WTF', 'http://syndication.thedailywtf.com/TheDailyWtf');
CREATE TABLE IF NOT EXISTS `items` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`source_id` int(10) unsigned NOT NULL,
`published` datetime NOT NULL,
`content` text NOT NULL,
`unique_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_id` (`unique_id`,`source_id`),
KEY `published` (`published`),
KEY `source_id` (`source_id`)
);
INSERT INTO `items` (`id`, `source_id`, `published`, `content`, `unique_id`) VALUES
(1, 1, '2009-12-01 16:25:53', 'Story about Subject One', 'abc'),
(2, 2, '2009-12-01 16:21:31', 'Subject One in story', 'abc'),
(3, 3, '2009-12-01 16:17:20', 'Techy goodness', 'def'),
(4, 2, '2009-12-01 16:05:57', 'Further updates on Foo case', 'ghi'),
(5, 3, '2009-12-01 15:53:39', 'Foo, Bar and Quux in court battle', 'ghi'),
(6, 2, '2009-12-01 15:52:02', 'Anti-Fubar protests cause disquiet', 'mno'),
(7, 4, '2009-12-01 15:39:00', 'Microsoft Bleh meets lukewarm reception', 'pqr'),
(8, 5, '2009-12-01 15:13:45', 'Ever thought about doing it in VB?', 'pqr'),
(9, 1, '2009-12-01 15:13:15', 'Celebrity has 'new friend'', 'pqr'),
(10, 1, '2009-12-01 15:09:57', 'Microsoft launches Bleh worldwide', 'stu'),
(11, 2, '2009-12-01 14:57:22', 'Microsoft launches Bleh in UK', 'stu'),
(12, 3, '2009-12-01 14:57:22', 'Microsoft launches Bleh', 'stu'),
(13, 3, '2009-12-01 14:42:15', 'Tech round-up', 'vwx'),
(14, 2, '2009-12-01 14:36:26', 'Estates 'old news' say government', 'yza'),
(15, 1, '2009-12-01 14:15:21', 'Iranian doctor 'was poisoned'', 'bcd'),
(16, 4, '2009-12-01 14:14:02', 'Apple fans overjoyed by iBlah', 'axf');
Ожидаемое содержимое после запроса:
- Рассказ о Субъекте
- Тече Боже
- Фу, Бар и Кукс в суде
- Протесты против Фубара вызывают беспокойство
- Microsoft Bleh встречает теплый прием
- Вы когда-нибудь думали сделать это в VB?
- У знаменитости появился новый друг
- Microsoft выпускает Bleh по всему миру
- Технический обзор
- Состояния "старые новости" говорят правительство
- Иранский доктор "отравлен"
- Поклонники Apple в восторге от iBlah
Я попробовал вариант решения от Andomar, но с некоторым успехом:
SELECT s.`name` AS `source`,
i.`content`,
i.`published`
FROM `items` i
INNER JOIN `sources` s
ON i.`source_id` = s.`id`
AND s.`active` = 1
INNER JOIN (
SELECT `unique_id`, `source_id`, MAX(`location_priority`) AS `prio`
FROM `items` i
INNER JOIN `sources` s ON s.`id` = i.`source_id` AND s.`active` = 1
GROUP BY `location_id`, `unique_id`
) `filter`
ON i.`unique_id` = `filter`.`unique_id`
AND s.`location_priority` = `filter`.`prio`
ORDER BY i.`published` DESC
LIMIT 50
С AND s.location_priority = filter.prio
все работает почти так, как я хочу. Поскольку элемент может поступать из нескольких источников с одинаковым приоритетом, элементы могут повторяться. В этом случае дополнительный GROUP BY i.unique_id
во внешнем запросе делает работу, и я полагаю, что не имеет значения, какой источник "выиграет", если приоритеты равны.
Я попытался использовать AND i.source_id = filter.source_id
вместо этого, который почти работает (то есть устраняет лишние GROUP BY
), но не дает результатов из правильных источников. В приведенном выше примере он дает мне «Дальнейшие обновления по делу Foo» (источник «BBC News England»), а не «Foo, Bar и Quux в судебном сражении» (источник «BBC Technology News». Просмотр результатов внутреннего запрос, я получаю:
unique_id: 'ghi'
source_id: 2
prio: 15
Обратите внимание, что идентификатор источника неверен (ожидается: 3).