Расширенный запрос выбора SQL - PullRequest
7 голосов
/ 27 июля 2011
week      cookie
1         a
1         b
1         c
1         d
2         a 
2         b
3         a
3         c
3         d

В этой таблице указано, что кто-то посещает веб-сайт в определенную неделю. Каждый файл cookie представляет отдельное лицо.Каждая запись представляет кого-то посещать этот сайт в определенную неделю.Например, последняя запись означает, что «d» пришло на сайт на неделе 3.

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

Например, если я посмотрю на неделю 1. Я получу результат как:

1 | 4
2 | 2
3 | 1

Поскольку 4 пользователя пришли на неделе 1. Только 2они (а, б) вернулись на неделе 2. Только 1 (а) из них пришли за все эти 3 недели.

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

Ответы [ 6 ]

3 голосов
/ 27 июля 2011

В этом запросе используются переменные для отслеживания соседних недель и определения их последовательности:

set @start_week = 2, @week := 0, @conseq := 0, @cookie:='';
select conseq_weeks, count(*)
from (
select 
  cookie,
  if (cookie != @cookie or week != @week + 1, @conseq := 0, @conseq := @conseq + 1) + 1 as conseq_weeks,
  (cookie != @cookie and week <= @start_week) or (cookie = @cookie and week = @week + 1) as conseq,
  @cookie := cookie as lastcookie,
  @week := week as lastweek
from (select week, cookie from webhist where week >= @start_week order by 2, 1) x
) y
where conseq
group by 1;

Это для недели 2. Для другой недели измените переменную start_week вверху.

Вот тест:

create table webhist(week int, cookie char);
insert into webhist values (1, 'a'), (1, 'b'), (1, 'c'), (1, 'd'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'c'), (3, 'd');

Вывод вышеуказанного запроса с помощью where week >= 1:

+--------------+----------+
| conseq_weeks | count(*) |
+--------------+----------+
|            1 |        4 |
|            2 |        2 |
|            3 |        1 |
+--------------+----------+

Вывод вышеуказанного запроса с помощью where week >= 2:

+--------------+----------+
| conseq_weeks | count(*) |
+--------------+----------+
|            1 |        2 |
|            2 |        1 |
+--------------+----------+

ps Хороший вопрос, но немного разбил мяч

2 голосов
/ 28 июля 2011

Это интересный.

Я пытаюсь выяснить, когда была последняя неделя, которую посетил каждый человек.
Это рассчитывается как первая неделя в начале или после начала, когда следующая неделя не посещалась.

Когда вы знаете последнюю неделю посещения каждого пользователя, вы просто подсчитываете за каждую неделю количество разных пользователей, чей последний визит был на этой неделе или позже.

SELECT wks.week, COUNT(cookie) as Visitors
FROM (SELECT a.cookie, MIN(a.week) AS FinalVisit
      FROM WeekVisits a 
           INNER JOIN WeekVisits FirstWeek
           ON a.cookie = FirstWeek.cookie
      WHERE a.week >= 1
        AND FirstWeek.week = 1
        AND NOT EXISTS (SELECT 1 
                        FROM WeekVisits b
                        WHERE b.week = a.week + 1
                          AND b.cookie = a.cookie)
      GROUP BY a.cookie) fv
     INNER JOIN
     (SELECT DISTINCT week 
      FROM WeekVisits
      WHERE week >= 1) wks
     ON fv.FinalVisit >= wks.week 
GROUP BY wks.week
ORDER BY wks.week

РЕДАКТИРОВАТЬ
-Благодаря ypercube за внимание.Я также потерял группу из запроса "fv".Упс.
-Я удалил комментарии, обозначающие параметры.
-Я удалил ненужные отличия.
РЕДАКТИРОВАТЬ еще раз
-Добавлен дополнительный материал для FirstWeek, потому чтоон не справился с началом на неделе 2

Когда я запускаю это (по общему признанию в MS Access)

, начиная с недели 1, я получаю:

+------+----------+
| week | Visitors |
|  1   |   4      |
|  2   |   2      |
|  3   |   1      |
+------+----------+

, начиная с недели 2Я получаю:

+------+----------+
| week | Visitors |
|  2   |   2      |
|  3   |   1      |
+------+----------+

.. как и ожидалось.
(Для начала на 2-й неделе вы бы изменили 1 на 2 в трех местах, где он сравнивается со столбцом недели)
Theметод кажется правильным, но синтаксис может потребоваться настроить для MySQL.

2 голосов
/ 27 июля 2011

По некоторым причинам большинство из этих ответов очень сложны, для них не нужны курсоры, циклы или что-то в этом роде ...

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

Если вы хотите узнать, сколько пользователей за каждую неделю посетили одну неделю, а затем неделю после каждого будущегонеделя:

SELECT visits.week, COUNT(1) AS [NumRepeatUsers]
FROM visits 
WHERE EXISTS (
    SELECT TOP 1 1 
    FROM visits AS nextWeek 
    WHERE nextWeek.week = visits.week+1 
      AND nextWeek.cookie = visits.cookie
  )
  AND EXISTS (
    SELECT TOP 1 1 
    FROM visits AS searchWeek
    WHERE searchWeek.week = @week 
      AND nextWeek.cookie = visits.cookie
  )
GROUP BY visits.week
ORDER BY visits.week

Однако это не покажет вам убывающих результатов с течением времени, если у вас будет 10 пользователей на неделе 1, а затем 5 разных пользователей, посещенных в течение следующих 5 недель, которые вы продолжали бы видеть 1 = 10,2= 5,3 = 5,4 = 5,5 = 5,6 = 5 и т. Д. Вместо этого вы хотите видеть, что 5 = x, где x - это число пользователей, которые посещали каждую неделю в течение 5 недель подряд.Для этого см. Ниже:

SELECT visits.week, COUNT(1) AS [NumRepeatUsers]
FROM visits 
WHERE EXISTS (
    SELECT TOP 1 1 
    FROM visits AS nextWeek 
    WHERE nextWeek.week = visits.week+1 
      AND nextWeek.cookie = visits.cookie
  )
  AND EXISTS (
    SELECT TOP 1 1 
    FROM visits AS searchWeek
    WHERE searchWeek.week = @week 
      AND nextWeek.cookie = visits.cookie
  )
  AND visits.week - @week = (
    SELECT COUNT(1) AS [Count]
    FROM visits AS searchWeek
    WHERE searchWeek.week BETWEEN @week+1 AND visits.week
      AND nextWeek.cookie = visits.cookie
  )
GROUP BY visits.week
ORDER BY visits.week

Это даст вам 1 = 10,2 = 5,3 = 4,4 = 3,5 = 2,6 = 1 или подобное

0 голосов
/ 27 июля 2011

Это мое решение, оно не совсем простое, но, как я уже проверял, оно решает вашу проблему:

Сначала мы объявляем хранимую процедуру, которая даст нам посетителя за определенную неделю, разделенную строками., вы можете использовать group_concat, если хотите, но я сделал так: учтите, что group_concat имеет ограничение текста.

DELIMITER $$

DROP PROCEDURE IF EXISTS `db`.`get_visitors_for_week`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `get_visitors_for_week`(id_week INTEGER, OUT result TEXT)
BEGIN
    DECLARE should_continue INT DEFAULT 0;
    DECLARE c_cookie CHAR(1);
    DECLARE r CURSOR FOR SELECT v.cookie
                FROM visits v WHERE v.week = id_week;
    DECLARE CONTINUE HANDLER FOR NOT FOUND
        SET should_continue = 1;
    OPEN r;
    REPEAT
        SET c_cookie = NULL;
        FETCH r INTO c_cookie;
        IF c_cookie IS NOT NULL THEN
            IF result IS NULL OR result = '' THEN
                SET result = c_cookie;
            ELSE SET result = CONCAT(result,',',c_cookie);
            END IF;
        END IF;
        UNTIL should_continue = 1
    END REPEAT;
    CLOSE r;
    END$$

DELIMITER ;

Затем мы объявляем функцию для переноса этой хранимой процедуры, чтобы мы могли вызывать ее внутри.Удобный запрос:

DELIMITER $$

DROP FUNCTION IF EXISTS `db`.`concat_values`$$

CREATE DEFINER=`root`@`localhost` FUNCTION `concat_values`(id_week INTEGER) RETURNS TEXT CHARSET latin1
BEGIN
    DECLARE result TEXT;
    CALL get_visitors_for_week(id_week, result);
    RETURN result;
    END$$

DELIMITER ;

И затем мы должны подсчитать посетителей, которые пришли на этой неделе и на прошлой неделе - для каждой недели курса - мы «видим», что, ища нашу строку cookie в объединеннойсписок.Это последний запрос:

SELECT
  v.week,
  SUM(IF(IFNULL(concat_values(v.week - 1)) OR INSTR(concat_values(v.week - 1),v.cookie) > 0, 1, 0)) AS Visitors
FROM (SELECT
        v.week,
        v.cookie,
        vt.visitors
      FROM visits v
        INNER JOIN (SELECT DISTINCT
                      v.week,
                      concat_values(v.week) AS visitors
                    FROM visits v) AS vt
          ON v.week = vt.week) AS v
WHERE v.week >= 1
GROUP BY v.week

Подставьте условие v.week >= 1 -the 1- для номера недели, с которого вы хотите начать.

0 голосов
/ 27 июля 2011

Используйте самостоятельное соединение:

SELECT ... FROM visits AS v1 LEFT JOIN visits AS v2 ON v2.week = v1.week+1
WHERE v2.week IS NOT NULL
GROUP BY cookie

Это даст вам записи о повторных и более поздних посещениях.

Но я думаю, что лучше было бы просто GROUP BY cookie, что поможет вамколичество посещений на файл cookie;любой номер выше 1 является возвращающимся пользователем.

0 голосов
/ 27 июля 2011

Хорошо, допустим, ваша таблица называется visits, и вас интересует номер недели n.Вы хотите знать, для каждой номера недели w >= n, какие пользователи появляются в каждую одну такую ​​неделю w.

Так сколько таких недель существует??

select count(*)
from visits
where week >= n;

А сколько таких недель посещал каждый пользователь?

select user, count(user)
from visit
group by user
where week >= n;

Предположим, у вас есть недели 1, 3, 4, 5, 6, 7, 9, 10,и 13, и вас интересует 5-я неделя. Итак, первый запрос, приведенный выше, дает вам 6, потому что есть 6 недель интереса: 5, 6, 7, 9, 10 и 13. Второй запрос даст вам, для каждогоПользователь, сколько из этих недель они посетили. Теперь вы хотите узнать, сколько из этих пользователей насчитывает 6.

Я думаю, что это работает:

select user, count(user)
from visit
group by user
having count(user) = (
    select count(*)
    from visits
    where week >= n)
where week >= n;

но я не знаюУ меня нет доступа к MySQL прямо сейчас.Если это не сработает, то, возможно, подход имеет смысл и направит вас в правильном направлении.РЕДАКТИРОВАТЬ: я смогу проверить завтра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...