在子查询中分组并计数

时间:2014-02-16 22:13:32

标签: mysql sql subquery

我正在尝试使用从(users_status表)中的数据派生的条件过滤掉我的(用户表)数据。

用户表是一个包含用户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中的最后一个条目“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 所以给定 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_id(3) 返回,因为user_status中没有 注意:原始的sql小提琴示例中没有添加user_id 3

4 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分: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

答案 2 :(得分: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)

答案 3 :(得分:1)

以下假设用户可以同时为不同的群组设置不同的书签状态。

找到每个(user_id,group_id)组合的最新日期,然后找到与其对应的记录。

根据'off'子句的规定,书签必须为NULLWHERE

由于使用user_groupLEFT JOIN中没有记录的用户可能会被退回。

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