Мне нужно написать запросы, чтобы найти новых пользователей и постоянных пользователей .

новые пользователи - это те, чей uuid появился за последние 24 часа (с этого момента минус время, когда запрос был запущен) в table2 и не был там раньше.

Обычные пользователи - это те, чей uuid появился в последний день table2 и был там хотя бы один раз за последние 3 дня.

В дополнение к этому будут рассматриваться только записи с id > 10 и ip != 2.

table1 - временная таблица, содержащая даты. Я не могу понять, как этого добиться с помощью объединений. Помогите, пожалуйста.


Таблица 2

    +----+---------------------+------+------+
    | id | ts                  | uuid | ip   |
    +----+---------------------+------+------+
    |  1 | 2010-01-10 00:00:00 | uid1 |    5 |
    |  2 | 2010-01-10 00:00:00 | uid2 |   14 |
    |  3 | 2010-01-10 00:00:00 | uid3 |   11 |
    |  4 | 2010-01-11 00:00:00 | uid4 |   16 |
    |  5 | 2010-01-11 00:00:00 | uid5 |    4 |
    |  6 | 2010-01-13 00:00:00 | uid6 |    2 |
    |  7 | 2010-01-10 00:00:00 | uid1 |    1 |
    |  8 | 2010-01-11 00:00:00 | uid2 |   10 |
    |  9 | 2010-01-12 00:00:00 | uid1 |    1 |
    | 10 | 2010-01-13 00:00:00 | uid4 |    1 |
    | 11 | 2010-01-09 21:00:00 | uid1 |    1 |
    | 12 | 2010-01-09 21:30:00 | uid1 |    2 |
    | 13 | 2010-01-10 05:00:00 | uid2 |    3 |
    | 14 | 2010-01-10 12:00:00 | uid1 |    1 |
    | 15 | 2010-01-10 12:00:00 | uid3 |    1 |
    | 16 | 2010-01-10 21:00:01 | uid1 |    7 |
    | 17 | 2010-01-11 01:00:00 | uid2 |   14 |
    | 18 | 2010-01-11 05:00:00 | uid2 |   11 |
    | 19 | 2010-01-11 17:59:00 | uid4 |   13 |
    | 20 | 2010-01-11 06:00:00 | uid5 |   12 |
    | 21 | 2010-01-11 18:01:00 | uid1 |   14 |
    | 22 | 2010-01-12 23:05:00 | uid4 |   17 |
    | 23 | 2010-01-13 12:01:23 | uid6 |   13 |
    +----+---------------------+------+------+
    23 rows in set (0.00 sec)

Таблица 1

    +------------+
    | ts         |
    +------------+
    | 2010-01-10 |
    | 2010-01-11 |
    | 2010-01-12 |
    | 2010-01-13 |
    +------------+
    4 rows in set (0.00 sec)

Вывод в случае новых пользователей взят в 18:00

+------------+-------+
| ts         | users |
+------------+-------+
| 2010-01-10 |     3 |
| 2010-01-11 |     2 |
| 2010-01-12 |     0 |
| 2010-01-13 |     1 |
+------------+-------+
4 rows in set (0.00 sec)

Дамп таблицы MySQL

DROP TABLE IF EXISTS `table1`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `table1` (
  `ts` date NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

INSERT INTO `table1` VALUES ('2010-01-10'),('2010-01-11'),('2010-01-12'),('2010-01-13');

DROP TABLE IF EXISTS `table2`;
CREATE TABLE `table2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ts` datetime DEFAULT NULL,
  `uuid` varchar(20) DEFAULT NULL,
  `ip` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=24 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

INSERT INTO `table2` VALUES (1,'2010-01-10 00:00:00','uid1',5),(2,'2010-01-10 00:00:00','uid2',14),(3,'2010-01-10 00:00:00','uid3',11),(4,'2010-01-11 00:00:00','uid4',16),(5,'2010-01-11 00:00:00','uid5',4),(6,'2010-01-13 00:00:00','uid6',2),(7,'2010-01-10 00:00:00','uid1',1),(8,'2010-01-11 00:00:00','uid2',10),(9,'2010-01-12 00:00:00','uid1',1),(10,'2010-01-13 00:00:00','uid4',1),(11,'2010-01-09 21:00:00','uid1',1),(12,'2010-01-09 21:30:00','uid1',2),(13,'2010-01-10 05:00:00','uid2',3),(14,'2010-01-10 12:00:00','uid1',1),(15,'2010-01-10 12:00:00','uid3',1),(16,'2010-01-10 21:00:01','uid1',7),(17,'2010-01-11 01:00:00','uid2',14),(18,'2010-01-11 05:00:00','uid2',11),(19,'2010-01-11 17:59:00','uid4',13),(20,'2010-01-11 06:00:00','uid5',12),(21,'2010-01-11 18:01:00','uid1',14),(22,'2010-01-12 23:05:00','uid4',17),(23,'2010-01-13 12:01:23','uid6',13);
3
Amit 17 Янв 2010 в 17:33
Теперь это , как задать вопрос БД. Очистить, с образцами данных, готовыми к копированию и вставке.
 – 
T.J. Crowder
17 Янв 2010 в 17:51
Кроме: Для чего table2? Чтобы ограничить диапазон дат, для которых вы получите эту информацию?
 – 
T.J. Crowder
17 Янв 2010 в 17:56
На самом деле вы неправильно пометили свои таблицы. Для чего нужна таблица дат (table2 в вашем тексте, table1 в примере)?
 – 
T.J. Crowder
17 Янв 2010 в 18:07
Я ошибся в таблицах :(. Теперь я это исправил.
 – 
Amit
17 Янв 2010 в 18:12
Table1 ограничивает диапазон дат
 – 
Amit
17 Янв 2010 в 18:14

2 ответа

Лучший ответ

Вы можете присоединиться к самой таблице для поиска записей того же пользователя, которым больше суток. Когда нет совпадений давности, поля в левой объединенной таблице будут ПУСТО (NULL).

Например:

select     
  YEAR(cur.ts) as year
, MONTH(cur.ts) as month
, DAY(cur.ts) as day
, case when old.uuid is null then 1 else 0 end as IsNewUser
, count(distinct cur.uuid) as Users
from       table2 cur
left join  table2 old
on         cur.uuid = old.uuid
           and old.ip <> 2
           and old.id > 10
           and cur.ts - old.ts > 1
where      cur.ip <> 2
           and cur.id > 10
group by   year, month, day, IsNewUser
order by   year, month, day, IsNewUser
2
Andomar 17 Янв 2010 в 18:05
Это работает на вашей установке? У меня, даже если я изменю timestamp на ts (чтобы соответствовать оригиналу), я все равно получаю «ОШИБКА 1054 (42S22): Неизвестный столбец 'old.uuid' в 'списке полей'».
 – 
T.J. Crowder
17 Янв 2010 в 17:54
@ T.J. Краудер: Набрав его из головы, я поменял местами table1 и table2. Отредактировано более качественной версией, хотя результат по-прежнему отличается от примера ответа в вопросе.
 – 
Andomar
17 Янв 2010 в 17:56
Да, это работает на моей машине. Но не могу понять, как меняю его под свои требования :(
 – 
Amit
17 Янв 2010 в 18:59

Я не очень хорошо знаком с MySQL, но вот как я бы сделал это в Oracle:

SELECT uuid, 'NEW' as user_type FROM
  (SELECT uuid, MAX(ts) as MAX_TS, MIN(ts) as MIN_TS
     FROM TABLE2
     WHERE ID > 10 AND
           IP <> 2
     GROUP BY uuid
     HAVING MAX_TS > SYSTIMESTAMP - INTERVAL '1' DAY AND
            MAX_TS = MIN_TS) nu
UNION ALL
  SELECT DISTINCT uuid, 'REGULAR' as user_type FROM
    (SELECT uuid, MAX(ts) as MAX_TS
       FROM TABLE2
       WHERE ID > 10 AND
             IP <> 2
       GROUP BY uuid) n
     INNER JOIN (SELECT *
                   FROM TABLE2
                   WHERE ID > 10 AND
                          IP <> 2) t
       ON (t.uuid = n.uuid)
     WHERE n.MAX_TS > SYSTIMESTAMP - INTERVAL '1' DAY AND
           t.ts < SYSTIMESTAMP - INTERVAL '1' DAY AND
           t.ts > SYSTIMESTAMP - INTERVAL '3' DAY;

Я не вижу здесь использования TABLE1. Обязательно ли это использовать?

Не знаю, поддерживает ли MySQL SYSTIMESTAMP или конструкцию INTERVAL. Надеюсь, это даст вам некоторые идеи.

1
Bob Jarvis - Reinstate Monica 17 Янв 2010 в 22:05
В таблице 1 могут быть дни, когда вообще нет записи. Итак, table1 используется в качестве начального числа для дат; и количество пользователей вычисляется по всем датам, указанным в таблице2.
 – 
Amit
17 Янв 2010 в 18:06