如何在LIMIT中将求和行计算为一行?

时间:2018-04-04 20:09:53

标签: mysql sql

我想根据这些规则选择用户的通知:

  • 所有未读通知
  • 始终有2个阅读通知
  • 至少15个通知(默认情况下)

这是我的查询,它获取用户的通知ID:

( SELECT id FROM events             -- all unread messages
  WHERE author_id = ? AND seen = 0  
) UNION
( SELECT id FROM events             -- 2 read messages
  WHERE author_id = ? AND seen <> 0
  ORDER BY date_time desc
  LIMIT 2                              
) UNION
( SELECT id FROM events             -- at least 15 rows by default
  WHERE author_id = ?
  ORDER BY seen, date_time desc
  LIMIT 15   
) 

然后我在上面的查询中选择匹配的ID以及其他类似的信息:(我不想因为某些原因将这两个查询合并在一起)

SELECT SUM(score) score, post_id, title, content, date_time
FROM events
GROUP BY post_id, title, content, date_time
ORDER BY seen, MAX(date_time) desc
WHERE id IN ($ids)

一切正常。

问题是:当第一个查询选择所有具有相同post_id的15行时,第二个查询会将它们相加并将其显示为一个通知行总得分。

我想我必须在第一个查询中添加SUM()吗?那GROUP BY?有什么想法吗?

问题的一个示例,如果用户获得15个upvotes,则第一个查询将其选为15个通知,第二个查询将其作为一个通知。如何获得15个单独的通知? (那些将在第二个查询中求和的通知应该算作第一个查询中的一个通知,如何?)

2 个答案:

答案 0 :(得分:1)

这不是答案,但评论的时间太长了:

你认为规则都很清楚,但是它们是什么?让我们说它不是至少15,但在最终结果中只需要至少5行。从下表中您需要ID 1,2,3和4,因为这些是未读的。但其他人呢?

id | score | post_id | title | content | date_time           | seen
---+-------+---------+-------+---------+---------------------+-----
1  |    10 |      11 | hello | it's me | 2018-01-11 12:34:56 |    0
2  |    20 |      22 | hello | it's me | 2018-01-12 12:34:56 |    0
3  |    30 |      33 | hello | it's me | 2018-01-13 12:34:56 |    0
4  |    40 |      44 | hello | it's me | 2018-01-14 12:34:56 |    0
5  |    50 |      11 | hello | it's me | 2018-01-11 12:34:56 |    1
6  |    60 |      22 | hello | it's me | 2018-01-12 12:34:56 |    1
7  |    70 |      44 | hello | it's me | 2018-01-14 12:34:56 |    1
8  |    80 |      55 | hello | it's me | 2018-01-05 12:34:56 |    1
9  |    90 |      55 | hello | it's me | 2018-01-05 12:34:56 |    1

对于相同的组有读取通知是否重要?它们比通知8和9更新是否重要?或者您只需将ID 8(或9?)添加到集合中并完成?

无论您选择ID 1,2,3,4还是8,或者您选择所有行,您最终都会有五个组。因此,请告诉我们您选择哪些ID以及原因。

答案 1 :(得分:1)

当你最终想要每组15行时,你应该对组有规则而不是我认为的消息。

您可以按组聚合数据,然后检查该组是否在您的结果中。您可以使用条件聚合在HAVING子句中执行此操作,即在条件表达式上使用的聚合函数。这是计算未读消息的一种方法,例如:

SUM(CASE WHEN seen = 0 THEN 1 ELSE 0 END)

这是另一个:

COUNT(CASE WHEN seen = 0 THEN 1 END)

(省略ELSE分支,默认为null,不计数。)

在MySQL中,这些表达式更简单,因为false等于0而true等于1.所以在MySQL中你会指望:

SUM(seen = 0)

您也可以使用其他聚合功能:

HAVING MAX(seen = 0) = 0 -- no unread messages

HAVING MIN(seen = 0) = 1 -- no read messages

现在让我们选择至少有一条未读消息的所有组:

SELECT SUM(score) AS score, post_id, title, content, date_time
FROM events
GROUP BY post_id, title, content, date_time
HAVING SUM(seen = 0) > 0;

(我们也可以使用HAVING MAX(seen = 0) = 1。)

现在使用UNION方法让所有群组至少有一条未读消息,并根据需要增加至少15个群组:

(
  SELECT SUM(score) AS score, post_id, title, content, date_time, SUM(seen = 0) as unread
  FROM events
  GROUP BY post_id, title, content, date_time
  HAVING SUM(seen = 0) > 0
)
UNION
(
  SELECT SUM(score) AS score, post_id, title, content, date_time, SUM(seen = 0) as unread
  FROM events
  GROUP BY post_id, title, content, date_time
  ORDER BY SUM(seen = 0) DESC, date_time DESC
  LIMIT 15
)
ORDER BY (unread = 0), date_time DESC;

如果您想要上述群组的单个ID,请使用IN

SELECT id
FROM events
WHERE (post_id, title, content, date_time) IN
(
  SELECT post_id, title, content, date_time
  FROM (<above query>) q
);