За да получите брой „Среден седмичен потребител“ (според моето разбиране на вашата спецификация... „за всеки ден, броят на отделните потребителски идентификатори, наблюдавани през този ден и предходните шест дни“), заявка по реда на този по-долу може да се използва. (Заявката връща и броя на „Среднодневен потребител“.
SELECT d.day
, COUNT(DISTINCT u.user_id) AS wau
, COUNT(DISTINCT IF(u.day=d.day,u.user_id,NULL)) AS dau
FROM ( SELECT FLOOR(k.ts/86400) AS `day`
FROM `log` k
GROUP BY `day`
) d
JOIN ( SELECT FLOOR(l.ts/86400) AS `day`
, l.user_id
FROM `log` l
GROUP BY `day`, l.user_id
) u
ON u.day <= d.day
AND u.day > d.day - 7
GROUP BY d.day
ORDER BY d.day
(Все още не съм тествал това; но ще го направя по-късно и ще актуализирам това изявление, ако са необходими някакви корекции.)
Тази заявка се присъединява към списъка с потребители за даден ден (от u
rowsource), към набор от дни от таблицата на журнала (d
източник на ред). Обърнете внимание на литерала „7“, който се появява в предиката за присъединяване (клаузата ON), това е, което „съпоставя“ списъка с потребители с предишните 6 дни.
Имайте предвид, че това може също да бъде разширено, за да получите отделния брой потребители през последните 3 дни, например чрез добавяне на друг израз в списъка SELECT.
, COUNT(DISTINCT IF(u.day<=d.day AND u.day>d.day-3,u.user_id,NULL)) AS 3day
Това буквално "7" може да бъде увеличено, за да се получи по-голям обхват. И този литерал 3 в израза по-горе може да бъде променен, за да получи произволен брой дни... просто трябва да сме сигурни, че имаме достатъчно редове от предишния ден (от d
) се присъединява към всеки ред от u
.
ЗАБЕЛЕЖКА ЗА ЕФЕКТИВНОСТ:Поради вградените изгледи (или извлечените таблици, както ги нарича MySQL), тази заявка може да не е много бърза, тъй като наборите от резултати за тези вградени изгледи трябва да бъдат материализирани в междинни MyISAM таблици.
Вграденият изглед с псевдоним като u
може да не е оптимално; може да е по-бързо да се присъедините директно към таблицата на журнала. Мислех по отношение на получаването на уникален списък с потребители за даден ден, което ме докара тази заявка във вградения изглед. Просто ми беше по-лесно да осмисля какво се случва. И си мислех, че ако сте въвеждали стотици от един и същи потребител за ден, вграденият изглед ще отсее цял куп дубликати, преди да направим присъединяването към другите дни. Клауза WHERE за ограничаване на броя на дните, през които се връщат най-добре да се добавят в u
и d
вградени изгледи. (d
вграденият изглед ще трябва да включва допълнителни по-ранни 6 дни.)
От друга забележка, ако колоната ts е тип данни TIMESTAMP, бих бил по-склонен да използвам DATE(ts)
израз за извличане на частта с дата. Но това ще върне тип данни DATE в набора от резултати, а не цяло число, което би било различно от набора от резултати, който сте посочили.)
SELECT d.day
, COUNT(DISTINCT u.user_id) AS wau
, COUNT(DISTINCT IF(u.day=d.day,u.user_id,NULL)) AS dau
FROM ( SELECT DATE(k.ts) AS `day`
FROM `log` k
GROUP BY `day`
) d
JOIN ( SELECT DATE(l.ts) AS `day`
, l.user_id
FROM `log` l
GROUP BY `day`, l.user_id
) u
ON u.day <= d.day
AND u.day > DATE_ADD(d.day, INTERVAL -7 DAY)
GROUP BY d.day
ORDER BY d.day