2014-02-16 95 views
1

我試圖用從(users_status表)中的數據派生的條件過濾掉我的(用戶表)數據。group by和在子查詢中計數

用戶表是一個包含用戶ID和用戶名

CREATE TABLE `users` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `username` varchar(25), 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

表由包含表組ID

CREATE TABLE `groups` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(25), 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

user_status表是一個表包含活動日誌。它的工作方式是當用戶在中時,用戶可以在「開」或「關」之間切換「加書籤」。

CREATE TABLE `user_status` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `group_id` int(10) unsigned, 
    `user_id` int(10) unsigned, 
    `bookmarked` enum('on', 'off'), 
    `date` datetime, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `group_id` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE, 
    CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE 
) ENGINE=InnoDB; 

現在我想要做的是檢索所有,要麼在user_status或user_status的最後一項中沒有任何條目的用戶來說是「關」

我有一個SQL小提琴與一個不完整的子查詢,我嘗試這樣做,但我沒有得到這個工作。 http://sqlfiddle.com/#!2/2d5b4/2

select us.id, us.group_id, g.name as GROUP_NAME, us.user_id, u.username as USER_USERNAME, us.bookmarked, us.date 
from user_status us 
inner join users u ON u.id = us.user_id 
inner join groups g ON g.id = us.group_id 
where 'on' != (
    select bookmarked 
    from user_status 
    group by (group_id, user_id) 
    where group_id = us.group_id AND user_id = us.user_id 
    order by ID DESC 
    limit 1; 
); 

EDIT下午6時28 因此,考慮user_status

select * from user_status order by group_id, user_id, date; 
+----+----------+---------+------------+--------------------------------+ 
| ID | GROUP_ID | USER_ID | BOOKMARKED |    DATE    | 
+----+----------+---------+------------+--------------------------------+ 
| 1 |  1 |  1 | on   | January, 16 2014 00:00:00+0000 | 
| 2 |  1 |  1 | off  | January, 17 2014 00:00:00+0000 | 
| 3 |  1 |  1 | on   | January, 18 2014 00:00:00+0000 | 
| 9 |  1 |  1 | on   | January, 18 2014 00:00:00+0000 | 
| 7 |  1 |  2 | on   | January, 16 2014 00:00:00+0000 | 
| 8 |  1 |  2 | off  | January, 17 2014 00:00:00+0000 | 
| 4 |  2 |  1 | on   | January, 16 2013 00:00:00+0000 | 
| 5 |  2 |  1 | off  | January, 17 2013 00:00:00+0000 | 
| 6 |  2 |  1 | on   | January, 18 2013 00:00:00+0000 | 
+----+----------+---------+------------+--------------------------------+ 

我希望

GROUP_ID(1)USER_ID(1) 沒有返回因爲最後加入書籤的是'on'

GROUP_ID(1)的user_id(2) 返回因爲最後書籤是 '關斷'

GROUP_ID(2)的user_id(1) 因爲最後書籤是 '上'

不返回

USER_ID(3) 返回因爲不存在於user_status 注:USER_ID 3在原來的SQL撥弄例如不添加

+0

請澄清。鑑於你的測試結果集,應該返回哪些用戶?用戶2的最後一個條目是'off',用戶3在'user_status'中有_no個條目_。是否應該返回一個或兩個? –

+0

請再次澄清:因爲user_id = 3應該返回group_id = 1和group_id = 2,user_id = 2應返回group_id = 2,因爲user_status中沒有行 –

+0

嗨Eugen,user_id = 3應該只返回一次因爲它在user_status中完全不存在。 – user391986

回答

1

以下假定一個用戶可以在同一時間對不同羣體的不同書籤狀態。

它找到每個(user_id,group_id)組合的最近日期,然後找到與之對應的記錄。

書籤需要是'off'NULL,如WHERE條款所規定的那樣。

由於使用了LEFT JOIN,因此user_group中沒有記錄的用戶可能會被退回。

SELECT 
    u.*, 
    g.*, 
    us.* 
FROM 
    users   AS u 
LEFT JOIN 
    (
    SELECT user_id, group_id, MAX(date) AS date 
    FROM user_status 
GROUP BY user_id, group_id 
) 
       AS us_newest 
    ON us_newest.user_id = u.id 
LEFT JOIN 
    user_status AS us 
    ON us.user_id = us_newest.user_id 
    AND us.group_id = us_newest.group_id 
    AND us.date  = us_newest.date 
LEFT JOIN 
    groups  AS g 
    ON g.id = us.group_id 
WHERE 
    us.bookmarked = 'off' 
    OR us.bookmarked IS NULL 
; 

http://sqlfiddle.com/#!2/2d5b4/26

+0

我最喜歡這個,它給了更多的空間進行有組織的調整,謝謝 – user391986

1

1 - 您使用group byWHERE條款

2 - 你被兩列在子查詢分組,而應該由一個列組

嘗試這方面的工作查詢

select us.id, us.group_id, g.name as GROUP_NAME, us.user_id, u.username as USER_USERNAME, us.bookmarked, us.date 
from user_status us 
inner join users u ON u.id = us.user_id 
inner join groups g ON g.id = us.group_id 
where 'on' != (
       select bookmarked 
       from user_status 

       where group_id = us.group_id AND user_id = us.user_id 
       group by (group_id) --->// you can choose to group by user_id or this. 
       order by ID DESC 
       limit 1 
      ); 

fiddle demo

+0

無語法錯誤,但不返回任何結果。 – MatBailie

+0

同樣沒有結果返回 – user391986

1

我想嘗試一個過濾連接,因爲這比帶有大數據集的子查詢要好得多:

SELECT DISTINCT 
    groups.id AS groupid, 
    users.id AS userid, 
    groups.name AS groupname 
FROM user_status 
INNER JOIN users ON user_status.user_id=users.id 
INNER JOIN groups ON user_status.group_id=groups.id 
LEFT JOIN 
    (SELECT 
    user_id, 
    group_id, 
    MAX(`date`) AS maxondate 
    FROM user_status 
    WHERE bookmarked='on' 
    GROUP BY user_id, group_id 
) AS ondate ON ondate.group_id=groups.id AND ondate.user_id=users.id 
LEFT JOIN 
    (SELECT 
    user_id, 
    group_id, 
    MAX(`date`) AS maxoffdate 
    FROM user_status 
    WHERE bookmarked='off' 
    GROUP BY user_id, group_id 
) AS offdate ON offdate.group_id=groups.id AND offdate.user_id=users.id 
WHERE 
    maxondate IS NULL 
    OR (
    maxondate IS NOT NULL 
    AND maxoffdate IS NOT NULL 
    AND maxondate<maxoffdate 
) 

SQLfiddle

+0

雖然這不會返回用戶3,但在'user_status'中沒有記錄。 –

+0

用戶三不在OP的測試數據 –

+0

正確。 _或者在user_status中沒有條目,或者user_status中的最後一個條目是「off」_因此用戶3應該被返回,不是? –

1

試試這個例子sqlfiddle

SELECT us.id, us.group_id, g.name AS GROUP_NAME, u.id AS user_id, u.username AS USER_USERNAME, us.bookmarked, us.date 
FROM users u 
LEFT OUTER JOIN user_status us ON u.id = us.user_id AND us.bookmarked = 'off' 
LEFT OUTER JOIN groups g ON g.id = us.group_id 
WHERE us.date = (SELECT max(ss.date) FROM user_status ss WHERE ss.user_id = us.user_id) 
OR NOT EXISTS (SELECT 1 FROM user_status ss WHERE ss.user_id = u.id) 
+0

這看起來非常簡單直接,謝謝你讓我測試一下更多 – user391986

+0

@ user391986那麼,這個解決方案對你有用嗎? –