1

我有两张桌子:

Members:

id     username    


Trips:

id    member_id     flag_status         created
                  ("YES" or "NO")

我可以做这样的查询:

SELECT 
  Trip.id, Trip.member_id, Trip.flag_status
FROM  
  trips Trip
WHERE   
  Trip.member_id = 1711
ORDER BY
  Trip.created DESC
LIMIT
  3

哪个可以给出这样的结果:

id       member_id     flag_status
8        1711          YES
9        1711          YES
10       1711          YES

我的目标是知道该成员的最后三趟旅行是否都有 flag_status = "YES",如果这三个中的任何一个 != "YES",那么我不希望它计算在内。

我还希望能够删除 WHERE Trip.member_id = 1711 子句,让它为我的所有成员运行,并给我最近 3 次旅行都具有 flag_status = "YES" 的成员总数

有任何想法吗?

谢谢!

http://sqlfiddle.com/#!2/28b2d

在那个 sqlfiddle 中,当我正在寻找的正确查询运行时,我应该看到如下结果:

 COUNT(Member.id)
        2

应该有资格的两个成员是成员 1 和 3。成员 5 失败,因为他的一次旅行有 flag_status = "NO"

4

2 回答 2

2

您可以使用 GROUP_CONCAT 函数,以获取按 id 升序排列的所有状态的列表:

SELECT
  member_id,
  GROUP_CONCAT(flag_status ORDER BY id DESC) as status
FROM
  trips
GROUP BY
  member_id
HAVING
  SUBSTRING_INDEX(status, ',', 3) NOT LIKE '%NO%'

然后使用 SUBSTRING_INDEX 您可以仅提取最后三个状态标志,并排除那些包含 NO 的标志。请在此处查看小提琴。我假设您的所有行都按 ID 排序,但是如果您有创建日期,则最好使用:

GROUP_CONCAT(flag_status ORDER BY created DESC) as status

正如雷蒙德建议的那样。然后,您还可以使用以下内容仅返回返回的行数:

SELECT COUNT(*)
FROM (
  ...the query above...
) as q
于 2013-11-09T16:34:08.543 回答
2

虽然我喜欢 fthiella 解决方案的简单性,但我就是想不出一个如此依赖数据表示的解决方案。为了不依赖它,您可以执行以下操作:

SELECT COUNT(*) FROM (
  SELECT member_id FROM (
    SELECT
      flag_status,
      @flag_index := IF(member_id = @member, @flag_index + 1, 1) flag_index,
      @member := member_id member_id
    FROM trips, (SELECT @member := 0, @flag_index := 1) init
    ORDER BY member_id, id DESC
  ) x
  WHERE flag_index <= 3
  GROUP BY member_id
  HAVING SUM(flag_status = 'NO') = 0
) x

在这里拉小提琴。注意我稍微修改了小提琴以删除其中一个用户。

该过程基本上根据每个成员的旅行对他们的旅行进行排名id desc,然后只保留最后 3 个。然后它确保所有获取的行程NO在 flag_status 中都没有 a。最后计算所有匹配的成员。

于 2013-11-09T17:09:00.507 回答