Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MySQL > Найти (если есть) разницу в двух таблицах


Автор: maxipub 12.1.2016, 19:14
Здравствуйте!

Есть:

Код
--
-- Структура таблицы `posts`
--

CREATE TABLE IF NOT EXISTS `posts` (
  `user_id` int(10) unsigned NOT NULL,
  `user_group` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

--
-- Дамп данных таблицы `posts`
--

INSERT INTO `posts` (`user_id`, `user_group`) VALUES
(1, 10),
(1, 20),
(1, 20),
(1, 20),
(2, 10),
(2, 10),
(2, 100);

-- --------------------------------------------------------

--
-- Структура таблицы `lists`
--

CREATE TABLE IF NOT EXISTS `lists` (
  `user_id` int(10) unsigned NOT NULL,
  `user_group` int(10) unsigned NOT NULL,
  `user_count` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

--
-- Дамп данных таблицы `lists`
--

INSERT INTO `lists` (`user_id`, `user_group`, `user_count`) VALUES
(1, 10, 1),
(1, 20, 2),
(2, 10, 2),
(2, 100, 2);


Мы имеем некоторые входные данные по парам user_id и user_group. И для этих данных нужно:

1) убедиться, что в таблице posts для указанного списка пар user_id и user_group есть lists.user_count записей (или больше);
2) если для какой-либо пары user_id и user_group предыдущее условие неверно, необходимо получить информацию об этом.

Например, входные данные по парам user_id и user_group:
1 10
1 20
2 100

Для первой lists.user_count = 1, и в posts есть 1 запись, значит все ок. Для второй пары lists.user_count = 2 в posts есть 3 записи - все ок. А вот для третей пары lists.user_count = 2, но в таблице posts есть только 1 запись. Вот об этом информацию нам и надо получить.

Это можно сделать MySQL решением? Одним запросом надо обрабатывать все пары user_id и user_group. Может уже вечер, но как бился, ничего не получается. Смотрю в сторону LEFT JOIN со сравнением COUNT, но пока без результатов. нужна свежая мысль. smile 

Автор: Akina 12.1.2016, 21:46
Цитата(maxipub @  12.1.2016,  20:14 Найти цитируемый пост)
Это можно сделать MySQL решением?

Конечно.
Код

SELECT l.*, COALESCE(pp.user_count,0) posts_count
FROM lists l
LEFT JOIN (
          SELECT p.user_id, p.user_group, COUNT(*) user_count
          FROM posts p
          GROUP BY p.user_id, p.user_group
          ) pp
     ON pp.user_id = l.user_id AND pp.user_group = l.user_group
WHERE COALESCE(pp.user_count,0) < l.user_count;

Автор: maxipub 13.1.2016, 11:01
Хм, группируем posts чтоб получить необходимые count-ы, джойним и делаем выборку по условию. Вроде бы все и очевидно, но вчера додуматься не удалось.

И такое еще уточнение, выборку нужно делать не для всех данных, а для определенных пар user_id и user_group. Я же правильно понимаю, что с точки зрения производительности, добавлять условие вида ((user_id=1 AND user_group=10) OR (user_id=1 AND user_group=20) ... ) в WHERE стоит и в выборке во временную таблицу pp, и в основном запросе одновременно? Обе таблицы, и lists, и posts не маленькие (но и не огромные).

Автор: Akina 13.1.2016, 11:05
Цитата(maxipub @  13.1.2016,  12:01 Найти цитируемый пост)
с точки зрения производительности, добавлять условие вида ((user_id=1 AND user_group=10) OR (user_id=1 AND user_group=20) ... ) в WHERE стоит и в выборке во временную таблицу pp, и в основном запросе одновременно?

Угу (во внутреннем оно лишнее по логике, но полезно с точки зрения производительности - возможно, обойдётся без материализации). А ещё разумнее слить их в temporary table с подходящим для такого отбора индексом.

Автор: maxipub 13.1.2016, 11:21
Спасибо, будем работать! smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)