2016-07-14 77 views
-1

我已經存儲發送給用戶的信息表,佈局如下選擇前N個消息按每個用戶接收

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

我試圖找到前N MESSAGE_ID的每個用戶已收到,但我完全卡住了。我可以在每個用戶的基礎上(在查詢中定義用戶ID時)輕鬆完成此操作,但不適用於全部用戶。

注意事項:

  • 許多用戶都可以得到相同的MESSAGE_ID
  • 消息ID的順序不被髮送
  • 這僅僅是一個讀(即我們可以消息200之前發送消息400) MySQL數據庫

編輯:關於第二個想法,我刪除這一點,但增加了它放回因爲有人還跟它

工作

最終目標是查看百分之多少用戶打開了他們收到的前N條消息之一。

的那臺打開這個樣子的:

user_id | message_id | datetime_opened 
+0

爲什麼不創建一個在db中插入消息日期的日期時間列? – Santiago

+0

@Santiago time_sent的列實際上是一個日期時間,而不僅僅是時間。編輯帖子澄清。另外,正如筆記中提到的那樣,它是一個只讀數據庫。 – Brandon

+0

您是否要求提供* all *用戶的百分比,或者只有那些收到至少一條消息的用戶? – 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

請評論如果和因爲這需要調整/進一步的細節。