2016-07-14 6 views
-1

У меня есть таблица, которая хранит сообщения, отправленные пользователями, раскладка выглядит следующим образомВыбрать первые N сообщений каждый пользователь получает

id (auto-incrementing) | message_id | user_id | datetime_sent 

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

Things отметить:

  • Многие пользователи могут получить тот же MESSAGE_ID
  • сообщений идентификаторы не передаются последовательно (т.е. мы можем послать сообщение 400 перед тем сообщением 200)
  • Это только для чтения базы данных MYSQL

EDIT: на второй мысли я удалил этот бит, но добавили его обратно, так как кто-то был достаточно любезен, чтобы работать на нем

Конечная цель - посмотреть, сколько% пользователей открыли одно из первых N сообщений, которые они получили.

Эта таблица открывается, выглядит так:

user_id | message_id | datetime_opened 
+0

Почему бы не создать столбец datetime с датой сообщения, вставленной в db? – Santiago

+0

@ Santiago столбец для time_sent на самом деле является датой, а не только временем. Отредактированное сообщение для уточнения. Кроме того, как упоминалось в примечаниях, это только чтение. – Brandon

+0

Вы просите процент всех * всех * пользователей или только тех, кто получил хотя бы одно сообщение? – trincot

ответ

0

Это непроверенный ответ на исходный вопрос (с 2-мя столами и условия на первых 5):

SELECT DISTINCT user_id 
FROM ( 
      SELECT  om.user_id, 
         om.message_id, 
         count(DISTINCT sm2.message_id) messages_before 
      FROM  opened_messages om 
      INNER JOIN sent_messages sm 
        ON om.user_id = sm.user_id 
        AND om.message_id = sm.message_id 
      LEFT JOIN sent_messages sm2 
        ON om.user_id = sm2.user_id 
        AND sm2.datetime_sent < sm.datetime_sent 
      GROUP BY om.user_id, 
         om.message_id 
      HAVING  messages_before < 5 
     ) AS base 

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

+0

Это потрясающе! Довольно точно, что мне нужно. вы не можете ждать, чтобы продолжить изучение вашего ответа. – Brandon

0

Чтобы получить первый N (здесь 2) сообщения, попробуйте

SELECT 
    user_id 
    , message_id 
FROM (
    SELECT 
    user_id 
    , message_id 
    , id 
    , (CASE WHEN @user_id != user_id THEN @rank := 1 ELSE @rank := @rank + 1 END) AS rank, 
     (CASE WHEN @user_id != user_id THEN @user_id := user_id ELSE @user_id END) AS _ 
    FROM (SELECT * FROM MessageSent ORDER BY user_id, id) T 
    JOIN (SELECT @cnt := 0) c 
    JOIN (SELECT @user_id := 0) u 
) R 
WHERE rank < 3 
ORDER BY user_id, id 
; 

, который использует RANK заменителя, полученный из @Seaux response в есть ли MySQL эквивалент «аналитических функций» Oracle,?

Чтобы расширить это к вашему первоначальному вопросу, просто добавьте соответствующий расчет:

SELECT 
    COUNT(DISTINCT MO.user_id) * 100/
    (SELECT COUNT(DISTINCT user_id) 
    FROM (
     SELECT 
     user_id 
     , message_id 
     , id 
     , (CASE WHEN @user_id != user_id THEN @rank := 1 ELSE @rank := @rank + 1 END) AS rank, 
      (CASE WHEN @user_id != user_id THEN @user_id := user_id ELSE @user_id END) AS _ 
     FROM (SELECT * FROM MessageSent ORDER BY user_id, id) T 
     JOIN (SELECT @cnt := 0) c 
     JOIN (SELECT @user_id := 0) u 
    ) R2 
    WHERE rank < 3 
    ) AS percentage_who_read_one_of_the_first_messages 
FROM MessageOpened MO 
JOIN 
    (SELECT 
     user_id 
     , message_id 
    FROM (
     SELECT 
     user_id 
     , message_id 
     , id 
     , (CASE WHEN @user_id != user_id THEN @rank := 1 ELSE @rank := @rank + 1 END) AS rank, 
      (CASE WHEN @user_id != user_id THEN @user_id := user_id ELSE @user_id END) AS _ 
     FROM (SELECT * FROM MessageSent ORDER BY user_id, id) T 
     JOIN (SELECT @cnt := 0) c 
     JOIN (SELECT @user_id := 0) u 
    ) R 
    WHERE rank < 3) MR 
    ON MO.user_id = MR.user_id 
    AND MO.message_id = MR.message_id 
; 

При отсутствии КТРА в MySQL, и быть в базе данных только для чтения - я не вижу пути вокруг, не имеющий приведенный выше запрос дважды в заявлении.

См. Его в действии: SQL Fiddle.

Прошу прокомментировать, если и для этого требуется настройка/дальнейшие детали.

Смежные вопросы