SQL: подсчет вернувшихся и новых посетителей на основе группы IP по дате

У меня есть график, показывающий мне уникальных посетителей на основе группы IP по дате (сегодня каждый час).

Теперь я хочу разделить эти данные для новых посетителей и вернувшихся посетителей по IP и session_id и сгруппировать их по дате (сегодня каждый час). Как я могу сделать это с помощью SQL-запроса? Это вообще возможно?

Запрос должен смотреть в таблице, если IP с session_id уже там. Значит, это возвращающийся посетитель. В противном случае это новый посетитель. Я не знаю, как это сделать.

Запрос Сегодня я должен подсчитать уникальные IP-адреса и сгруппировать их по часам:

SELECT DISTINCT DATE_FORMAT(`date`, '%Y-%m-%d %H') as 'dates', COUNT(DISTINCT `ip`) as 'count' FROM `logging` WHERE DATE(date) = DATE(NOW()) GROUP BY `dates`

Теперь он показывает мне:

Dates            Count
2021-02-04 00    10
2021-02-04 01    8
2021-02-04 02    5

и т.п.

Я хочу:

Dates            Count new IP      Count returning IP
2021-02-04 00    2                 8
2021-02-04 01    4                 4
2021-02-04 02    2                 3

Новый IP: проверьте, хранится ли IP в таблице только с одним известным session_id. Возврат IP: проверьте, хранится ли IP в таблице с несколькими разными идентификаторами session_id.

Спасибо заранее!

ОБНОВЛЕНИЕ №1:

Теперь у меня есть следующий запрос, чтобы подсчитать вернувшихся посетителей сегодня:

SELECT date, ip, count(distinct ip, session_id) as 'count' FROM logging GROUP BY ip HAVING count > 1 AND date(date) = date(now())

Результат например:

date                    ip                   count (returning visitors)
2021-02-05 08:24:56     62.163.91.178        2
2021-02-05 10:24:15     77.163.91.223        6
2021-02-05 08:49:51     77.173.17.157        13

Как я могу изменить этот запрос, чтобы сгруппировать их по дате, чтобы получить это ?:

date                    count (returning visitors)
2021-02-05 08           15
2021-02-05 10           6

ОБНОВЛЕНИЕ №2:

Благодаря Tsungur я отправил следующий запрос, но он показывает разные результаты каждый раз, когда я его запускаю.

select DATE_FORMAT([date], '%Y-%m-%d %H') as [date] , count(*) from ( SELECT [date], ip, count(distinct ip, session_id) as 'count' FROM logging GROUP BY ip HAVING count(distinct ip, session_id) > 1 AND date(date) = date(now())
) as sub
group by DATE_FORMAT([date], '%Y-%m-%d %H') 

Вот некоторые данные, с которыми можно поиграть:

ID        session_id                   ip               date
10752     454747k5k45l23h3b5n6k432nn   44.56.123.123    2021-01-01 09:15:54   
10950     kmcoq3glgm187uhsfmo3r71h9q   86.85.131.246    2021-02-11 13:19:22
10958     kmcoq3glgm187uhsfmo3r71h9q   86.85.131.246    2021-02-12 12:10:52
10960     dfh78dfh7fdh7fdh6sd55dsd88   86.85.131.246    2021-02-12 13:00:02
10967     87s97sfh57sh6sh6s6sdsd44d3   11.56.873.560    2021-02-13 13:00:00
10968     rkdrgjsd7gjsd5jskjd46kjdsk   66.35.127.435    2021-02-13 13:01:00
10977     rkdrgjsd7gjsd5jskjd46kjdsk   66.35.127.435    2021-02-13 13:03:11
10978     dfajesj9sdj0dfh78sgd57sd5d   44.56.123.123    2021-02-13 13:05:12
10979     fhdf7f7hdf6fd44fdf3ffdf321   86.85.131.246    2021-02-13 14:05:02
10980     fhdf7f7hdf6fd44fdf3ffdf321   86.85.131.246    2021-02-13 14:06:13

Приведенные выше данные должны показать мне:

date             count (new visitor)
2021-02-13 13    2
2021-02-13 14    0

date             count (returning visitor)
2021-02-13 13    1
2021-02-13 14    1

person Bas Verhagen    schedule 04.02.2021    source источник
comment
Да, это возможно; вам понадобится ВНЕШНЕЕ САМОСОЕДИНЕНИЕ или коррелированный подзапрос.   -  person PM 77-1    schedule 04.02.2021
comment
Отредактируйте свой вопрос и покажите желаемые результаты. Это одна таблица с тремя столбцами?   -  person Gordon Linoff    schedule 04.02.2021
comment
Какой продукт СУБД вы используете? SQL - это просто язык запросов, используемый всеми реляционными базами данных, а не имя конкретного продукта базы данных (первый запрос, похоже, указывает на MySQL из-за ужасных обратных ссылок, но вторая часть, похоже, указывает на SQL-сервер из-за ужасных квадратных скобок) . Добавьте тег для используемого продукта базы данных. Зачем мне добавлять теги в СУБД   -  person a_horse_with_no_name    schedule 16.02.2021


Ответы (1)


Вы можете найти возвращаемые IP-адреса, сгруппировав по IP-адресам и отфильтровав их, количество которых больше одного.

SELECT [ip]
FROM [logging]
group by [ip]
having count(*)>1

Затем вы можете использовать этот запрос в качестве фильтра для вашего основного запроса.

SELECT [ip], [date],count(*) as [Count]
FROM [logging]
where [ip] in
(
SELECT [ip]
FROM [logging]
group by [ip]
having count(*)>1
)
group by [ip],[date]

Что касается последней части вашего обновленного вопроса;

  1. Ваш текущий запрос согласован. Вы показываете количество различных IP-адресов и сеансов, но ваше предложение не отражает этого. Ваше предложение Have рассчитывается по дате и группировке IP. Не уверен, специально ли вы это сделали. Может быть, ваша оговорка о наличии должна быть having count(distinct ip, session_id)>1.

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

    select DATE_FORMAT([date], '%Y-%m-%d %H') as [date] , count(*) from (
    SELECT [date], ip, count(distinct ip, session_id) as 'count' FROM logging GROUP BY ip HAVING count > 1 AND date(date) = date(now())
        ) as sub
        group by DATE_FORMAT([date], '%Y-%m-%d %H') 
    

ОБНОВЛЕНИЕ №2. Сначала совет: по возможности не используйте зарезервированные слова в качестве имен столбцов (например, дату). Пытался разбить проблему на части. Итоговый запрос выглядит грязным, его можно улучшить и сократить. Но для прояснения опасений я использовал несколько запросов. Ваша первая проблема - это подсчет уникальных sid и ip. Для простоты (поскольку оба являются строками) я использовал sid + ':' + ip как единственную уникальную строку. Еще одна проблема - группировка даты и часа. Итак, шаг за шагом:

  1. Создание базовых справочных данных:

         SELECT FORMAT(dt, 'yyyy-MM-dd HH') as dt_H,
           [sid]+':'+[ip] as uniq
    
       FROM [mytable]
       where cast(dt as date)=cast(getdate() as date)
    
  2. Поиск возвращаемых товаров по моей уникальной стоимости и дате - час:

    выберите dt_H, uniq, count () как раз из (SELECT FORMAT (dt, 'yyyy-MM-dd HH') as dt_H, [sid] + ':' + [ip] as uniq FROM [mytable] где cast (dt as date) = cast (getdate () as date)) как вспомогательная группа по dt_H, uniq имеет count () ›1

  3. Если вы используете php, вы можете позже разделить поле uniq символом:. Но если вы хотите, чтобы это было в sql, мы присоединимся к основной таблице без отличительных столбцов:

    выберите отдельный return.dt_H, main. [sid], main. [ip], return.times из [mytable] в качестве основного внутреннего соединения (выберите dt_H, uniq, count (*) как раз из (SELECT FORMAT (dt, 'yyyy -MM-dd HH ') как dt_H, [sid] +': '+ [ip] как uniq

           FROM [mytable]
           where cast(dt as date)=cast(getdate() as date)
     ) as helper
       group by dt_H,uniq
       having count(*)>1
    

    ) как возвращается при возврате. uniq = main. [sid] + ':' + main. [ip] и FORMAT (main.dt, 'yyyy-MM-dd HH') = return.dt_H

  4. Вы сказали, что вы заполняете пробелы с помощью PHP. Вы также можете сделать это в sql. Я бы предложил создать определяемую пользователем функцию (которая может пригодиться во многих других случаях), которая будет создавать числовые значения в заданном диапазоне: CREATE FUNCTION [dbo].[GetNumbers](@Start int, @Stop int) RETURNS TABLE AS RETURN WITH Numbers (N) AS ( SELECT @Start UNION ALL SELECT @Start + N-@Start+1 FROM Numbers WHERE N < @Stop ) SELECT N FROM Numbers GO

Использование:

SELECT N FROM [dbo].[GetNumbers] (0,23)

Это вернет таблицу со всеми часами дня. Вы можете использовать эту таблицу в сочетании с датой и левым соединением с указанным выше запросом. Таким образом, вы можете отображать все часы и 0 для времени возврата, если оно равно нулю.

PS: извините, не удалось заставить работать форматирование.

person TSungur    schedule 04.02.2021
comment
Спасибо! У меня также есть столбец с идентификатором сеанса. Можно ли считать IP только тогда, когда у них другой session_id? Вид сложно объяснить. - person Bas Verhagen; 06.02.2021
comment
Смотрите мое обновление поста :) - person Bas Verhagen; 06.02.2021
comment
Спасибо за обновление! Я пробовал ваш запрос, но каждый раз получаю разные результаты ... Я не знаю, что не так. - person Bas Verhagen; 12.02.2021
comment
Не могли бы вы показать образец ваших фактических данных перед любым запросом, включая первого и повторного посетителя - person TSungur; 13.02.2021
comment
Да, я могу. Проверьте мой пост :) - person Bas Verhagen; 13.02.2021
comment
Думаю, я наконец знаю, почему результаты иногда бывают разными. Когда кто-то является уникальным посетителем на счету сегодня 12.00. И он возвращается сегодня в 14.00 с новым сеансом. Он обращается к возвращающемуся посетителю на счет 12.00. Так что количество уникальных посетителей на 12.00 сокращается. Можно ли подсчитывать уникальных и вернувшихся посетителей до того часа, который покажет запрос, чтобы результаты были статичными и не менялись каждый раз? В противном случае большинство уникальных посетителей позже станут постоянными посетителями, и старые графики будут меняться каждый раз. - person Bas Verhagen; 13.02.2021
comment
На ум приходит много вопросов. Вы хотите, чтобы 2 запроса, один для возврата, один для новичков, или вы хотите видеть счетчики в одной строке и отдельном столбце для каждого значения? Еще один вопрос: что вы ожидаете увидеть, если нет данных за 2021-02-13 14? Ожидаете ли вы, что в строке будет нулевое количество строк или вообще не будет строки? Как вы определяете «уникальность». В своем вопросе вы написали «на основе IP-адреса и сеанса». Один и тот же IP-адрес с другим сеансом является новым посетителем (также что, если другой IP-адрес и тот же идентификатор сеанса)? - person TSungur; 14.02.2021
comment
Я понимаю вопросы. Это довольно сложно. Это должно быть два запроса. Один для новых посетителей (отдельный ip + session_id = 1) и один для вернувшихся посетителей (отдельный ip + session_id ›1). Я заполняю дыры php-скриптом, где посетители не могут рассчитывать на определенные часы. - person Bas Verhagen; 14.02.2021
comment
Обновил ответ - person TSungur; 16.02.2021