簡體   English   中英

分組並在子查詢中計數

[英]group by and count within a subquery

我正在嘗試使用從(users_status表)中的數據派生的條件來過濾掉(users表)數據。

users表是包含用戶標識和用戶名的表

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中的最后一個條目為“ off”的用戶。

我有一個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;
);

編輯6:28 pm所以給定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) 未返回,因為上一個標記為“ on”

由於user_status中不存在user_id(3)而返回注:在原始sql小提琴示例中未添加user_id 3

1-您在WHERE子句之前使用group by

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
              );

小提琴演示

我會嘗試過濾聯接,因為這比具有大數據集的子查詢要好得多:

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
  )

SQL小提琴

試試這個例子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)

以下假設用戶可以同時對不同的組具有不同的書簽狀態。

它找到每個(user_id,group_id)組合的最新日期,然后找到與其對應的記錄。

WHERE子句所示,書簽需要為'off'NULL

由於使用了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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM