5

这是表结构:

+----+-----------------------------+-----------+
| id |       post_content          | edited_id |
+----+-----------------------------+-----------+
| 1  | content 1                   | NULL      |
| 2  | content 2                   | NULL      |
| 3  | content 1 (edited)          | 1         |
| 4  | content 3                   | NULL      |
| 5  | content 4                   | NULL      |
| 6  | content 4 (edited)          | 5         |
| 7  | content 1 (edited)          | 1         |
+----+-----------------------------+-----------+

现在我想选择每篇文章的最新编辑版本。所以这是预期的结果:

+----+-----------------------------+-----------+
| id |       post_content          | edited_id |
+----+-----------------------------+-----------+
| 7  | content 1 (edited)          | 1         |
| 2  | content 2                   | NULL      |
| 4  | content 3                   | NULL      |
| 6  | content 4 (edited)          | 5         |
+----+-----------------------------+-----------+

我怎样才能做到这一点?

4

5 回答 5

3

SQL Fiddle看看它是如何工作的。

首先,我们删除" (edited)"字符串部分(如果需要),post_content为 group by 准备一列,然后计算id每个组的最大值,最后加入同一个表以检索特定的值id

SELECT
  goo.id,
  qa.post_content,
  qa.edited_id
FROM (
  SELECT
    MAX(id) AS id,
    post_content
  FROM (
    SELECT
      id,
      CASE WHEN locate(' (edited)', post_content) <> 0
           THEN left(post_content, locate(' (edited)', post_content) - 1)
           ELSE post_content
           END AS post_content,
      edited_id
    FROM qa
    ) foo
  GROUP BY post_content
  ) goo
  INNER JOIN qa ON goo.id = qa.id

输出

+----+-----------------------------+-----------+
| id |       post_content          | edited_id |
+----+-----------------------------+-----------+
| 7  | content 1 (edited)          | 1         |
| 2  | content 2                   | NULL      |
| 4  | content 3                   | NULL      |
| 6  | content 4 (edited)          | 5         |
+----+-----------------------------+-----------+

案例说明

-- if post_content contains " (edited)" then locate() will return value of it's position
CASE WHEN locate(' (edited)', post_content) <> 0
  -- we're removing the " (edited)" part by doing left()-1 because we want the string to finish before first character of " (edited)"
     THEN left(post_content, locate(' (edited)', post_content) - 1)
  -- if post_content doesn't contain " (edited)" then simply return post_content
     ELSE post_content
     END AS post_content
于 2016-08-27T20:48:02.833 回答
3

就像评论中建议的@PaulSpiegel 一样,我认为表结构的一个小改动会让你的生活更轻松。
我建议你改变你的edited_idwith content_id,并在所有记录上赋予它价值,包括原始记录。

您的数据将如下所示:

+----+-----------------------------+------------+
| id |       post_content          | content_id |
+----+-----------------------------+------------+
| 1  | content 1                   | 1          |
| 2  | content 2                   | 2          |
| 3  | content 1 (edited)          | 1          |
| 4  | content 3                   | 3          |
| 5  | content 4                   | 4          |
| 6  | content 4 (edited)          | 4          |
| 7  | content 1 (edited)          | 1          |
+----+-----------------------------+------------+

这样,您可以使用 content_id 作为内容的标识符,从而节省您处理空值的需要

查询将如下所示:

SELECT A.* from myTable as A INNER JOIN (
  SELECT max(id) as id, content_id from myTable group by content_id
) as B ON A.id = B.id 
 AND A.content_id = B.content_id
于 2016-08-27T21:04:04.107 回答
3

这应该有效:

select qa.*
from(
  select max(id) as max_post_id
  from qa
  group by coalesce(edited_id, id)
) maxids
join qa on qa.id = maxids.max_post_id

http://sqlfiddle.com/#!9/6018b2/1

如果您想通过以下方式订购edited_id

select qa.*
from(
  select max(id) as max_post_id, coalesce(edited_id, id) as edited_id
  from qa
  group by coalesce(edited_id, id)
) maxids
join qa on qa.id = maxids.max_post_id
order by maxids.edited_id

http://sqlfiddle.com/#!9/6018b2/9

于 2016-08-27T20:49:49.920 回答
2

尝试这个:

select * from qa
where id in (
    select max(id) from qa
        group by case when edited_id is not null then edited_id
        else id end
) 
order by case 
    when edited_id is null then id 
    else edited_id end;

这是小提琴:

http://sqlfiddle.com/#!9/6018b2/10/0

解释

内部查询负责完成所有工作,外部查询仅用于对结果进行排序。

内部查询说应该对包含的行进行分组edited_id,它应该分组edited_id,如果它没有被编辑,它应该分组id。当然,我们要求max(id)在分组时返回。

于 2016-08-27T21:02:48.430 回答
1
select max(id), post_content, edited_id from post where edited_id is not null group by edited_id
union
select id, post_content, edited_id from post where edited_id is null and id not in (select edited_id from post where edited_id is not null)
于 2016-08-27T20:35:37.137 回答