BoBka-altRUist
Новичок
Приветствую,
наверняка многие сталкивались с такой задачей есть таблица-журнал посещений пользователей своих аккаунтов в системе, нужно найти все возможные пересечения, выявить какие аккаунты могут принадлежать одному и тому же пользователю (упрощенно):
(эта задача кстати актуальна еще для такого случая когда есть таблица сообщений там адресаты и отправители и нужно например объединить пользователей в группы, как в соц. сетях)
logs_table:
самое простое сгруппировать по ip (исключая из внимания дату, т.е. за все время):
ip_rows ip
3 127.0.0.1
2 127.0.0.2
1 127.0.0.4
2 127.0.0.5
т.е. получили сколько вхождений по каждому ip; можно отобрать только те где количество вхождений >1
id ip user_id data ip_rows ip0
1 127.0.0.1 8 2014-08-13 3 127.0.0.1
2 127.0.0.1 1 2014-08-13 3 127.0.0.1
3 127.0.0.1 2 2014-08-13 3 127.0.0.1
4 127.0.0.2 2 2014-08-13 2 127.0.0.2
5 127.0.0.2 3 2014-08-13 2 127.0.0.2
7 127.0.0.5 7 2014-08-16 2 127.0.0.5
8 127.0.0.5 10 2014-08-17 2 127.0.0.5
с отступами:
Но в данном случае находим пересечения только явно по ip (выделил разным цветом), а как найти пересечение по аккаунту user_id=2 выделено жирным (это строки id=3 и id=4) тогда получится что группа строк выделенных красным объединиться с группой строк синих.
----------------------------
у меня приходит мысль сделать что-то типа логического произведения таблицы самой на себя, т.е.:
находим по таблице повторные user_id, где user_id>1 (это user_id=2) получаем массив ip где user_id=2 (это: 127.0.0.2 и 127.0.0.1)
в цикле по этим ip проходим по всей таблице находя строки с этими ip-адресами где user_id<>2 и дописываем в исходную таблицу строки где ip=ip-адресам из массива (исключая искомый), а user_id=user_id-в найденной строке.
т.е. для ip = 127.0.0.2 и user_id<>2:
находим строки id=5, user_id у этой строки = 3 вставляем строку ip=127.0.0.1 | user_id=3
для ip = 127.0.0.1 и user_id<>2:
находим строки id=1, id=2, соответственно добавляем строки
ip=127.0.0.2 | user_id=8
ip=127.0.0.2 | user_id=1
после данных манипуляций к таблице можно применить тотже метод что описан вначале и по идее будут найдены все пересечения,
проблема в том что как это сделать понимаю используя манипуляции на php, можно ли это упростить используя mysql запросы? и вообще может я изобретаю велосипед и давно уже есть какой-нибудь способ группировки group by по двум полям (используя логическое ИЛИ для этих полей - это было бы отличным решением)
и еще не совсем понимаю как еще при этом учитывать дату... ( т.е. мои размышления если и работают то только для всей таблицы, а если нужно взять к примеру за число 2014-08-13 ...
или может быть таблицу делать избыточной по всем датам (запуская по cron-у отмечая обработанные строки) и дату вставляемых строк указывать относительно найденных записей...
з.ы. возможно я тут нагородил, надеюсь кто-то поймет что я хотел сказать.
наверняка многие сталкивались с такой задачей есть таблица-журнал посещений пользователей своих аккаунтов в системе, нужно найти все возможные пересечения, выявить какие аккаунты могут принадлежать одному и тому же пользователю (упрощенно):
(эта задача кстати актуальна еще для такого случая когда есть таблица сообщений там адресаты и отправители и нужно например объединить пользователей в группы, как в соц. сетях)
logs_table:
Код:
ip user_id data
127.0.0.1 8 2014-08-13
127.0.0.1 1 2014-08-13
127.0.0.1 2 2014-08-13
127.0.0.2 2 2014-08-13
127.0.0.2 3 2014-08-13
127.0.0.4 6 2014-08-16
127.0.0.5 7 2014-08-16
127.0.0.5 10 2014-08-17
Код:
CREATE TABLE IF NOT EXISTS `logs_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(11) NOT NULL,
`data` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=9 ;
--
-- Дамп данных таблицы `logs_table`
--
INSERT INTO `logs_table` (`id`, `ip`, `user_id`, `data`) VALUES
(1, '127.0.0.1', 8, '2014-08-13'),
(2, '127.0.0.1', 1, '2014-08-13'),
(3, '127.0.0.1', 2, '2014-08-13'),
(4, '127.0.0.2', 2, '2014-08-13'),
(5, '127.0.0.2', 3, '2014-08-13'),
(6, '127.0.0.4', 6, '2014-08-16'),
(7, '127.0.0.5', 7, '2014-08-16'),
(8, '127.0.0.5', 10, '2014-08-17');
самое простое сгруппировать по ip (исключая из внимания дату, т.е. за все время):
Код:
SELECT COUNT( id ) AS ip_rows, logs_table.ip
FROM `logs_table`
GROUP BY ip
3 127.0.0.1
2 127.0.0.2
1 127.0.0.4
2 127.0.0.5
т.е. получили сколько вхождений по каждому ip; можно отобрать только те где количество вхождений >1
Код:
SELECT *
FROM logs_table, (
SELECT COUNT( id ) AS ip_rows, logs_table.ip ip0
FROM `logs_table`
GROUP BY ip
)q1
WHERE ip_rows >1
AND `logs_table`.`ip` = ip0
1 127.0.0.1 8 2014-08-13 3 127.0.0.1
2 127.0.0.1 1 2014-08-13 3 127.0.0.1
3 127.0.0.1 2 2014-08-13 3 127.0.0.1
4 127.0.0.2 2 2014-08-13 2 127.0.0.2
5 127.0.0.2 3 2014-08-13 2 127.0.0.2
7 127.0.0.5 7 2014-08-16 2 127.0.0.5
8 127.0.0.5 10 2014-08-17 2 127.0.0.5
с отступами:
Код:
id ip user_id data ip_rows ip0
1 127.0.0.1 8 2014-08-13 3 127.0.0.1
2 127.0.0.1 1 2014-08-13 3 127.0.0.1
3 127.0.0.1 2 2014-08-13 3 127.0.0.1
4 127.0.0.2 2 2014-08-13 2 127.0.0.2
5 127.0.0.2 3 2014-08-13 2 127.0.0.2
7 127.0.0.5 7 2014-08-16 2 127.0.0.5
8 127.0.0.5 10 2014-08-17 2 127.0.0.5
----------------------------
у меня приходит мысль сделать что-то типа логического произведения таблицы самой на себя, т.е.:
находим по таблице повторные user_id, где user_id>1 (это user_id=2) получаем массив ip где user_id=2 (это: 127.0.0.2 и 127.0.0.1)
в цикле по этим ip проходим по всей таблице находя строки с этими ip-адресами где user_id<>2 и дописываем в исходную таблицу строки где ip=ip-адресам из массива (исключая искомый), а user_id=user_id-в найденной строке.
т.е. для ip = 127.0.0.2 и user_id<>2:
находим строки id=5, user_id у этой строки = 3 вставляем строку ip=127.0.0.1 | user_id=3
для ip = 127.0.0.1 и user_id<>2:
находим строки id=1, id=2, соответственно добавляем строки
ip=127.0.0.2 | user_id=8
ip=127.0.0.2 | user_id=1
после данных манипуляций к таблице можно применить тотже метод что описан вначале и по идее будут найдены все пересечения,
проблема в том что как это сделать понимаю используя манипуляции на php, можно ли это упростить используя mysql запросы? и вообще может я изобретаю велосипед и давно уже есть какой-нибудь способ группировки group by по двум полям (используя логическое ИЛИ для этих полей - это было бы отличным решением)
и еще не совсем понимаю как еще при этом учитывать дату... ( т.е. мои размышления если и работают то только для всей таблицы, а если нужно взять к примеру за число 2014-08-13 ...
или может быть таблицу делать избыточной по всем датам (запуская по cron-у отмечая обработанные строки) и дату вставляемых строк указывать относительно найденных записей...
з.ы. возможно я тут нагородил, надеюсь кто-то поймет что я хотел сказать.
Последнее редактирование: