2016-08-27 5 views
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   | 
+----+-----------------------------+-----------+ 

Как я могу это сделать?

+0

Как вы определяете "последний" и "каждый пост"? –

+0

@PaulSpiegel Последняя версия каждого сообщения - это тот, который имеет более высокий идентификатор, чем другие. Также исходный пост - это тот, который имеет 'edit_id = NULL'. –

+3

Вы должны изменить свой дизайн db и сделать вашу жизнь проще. –

ответ

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) 
+0

[Не работает] (http://sqlfiddle.com/#!9/13236f/5). –

+0

Вы можете показать результат этого запроса? –

+0

Я сделал .. комментарий выше - это скрипка вашего запроса. –

3

SQL Fiddle, чтобы увидеть, как это работает.

Сначала мы удалим " (edited)" часть строки (в случае необходимости) с post_content в preapre колонки для группы пути, в то вычисления максимального 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 
+0

Odd .. где 'id = 7' содержимое« содержимое 1 (отредактировано) ». Но в результате, где' id = 7', содержимое является «содержимым 1». –

+0

Хорошая точка! Исправлена. Просто нужно изменить 'goo.post_content' на' qa.post_content'. Это связано с тем, что мы усекали «отредактированную» часть и, следовательно, нам нужно получить исходное значение из таблицы так же, как мы делаем для 'edit_id' –

+0

Кажется хорошим .. спасибо .. upvote –

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

+0

Звучит неплохо, upvote .. Просто порядок не похож на ожидаемый ... –

+0

В нашем вопросе ничего не говорится. Что вы хотите заказать? –

+0

[Ожидаемый результат.] (Http://i.stack.imgur.com/XnP2d.png) –

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) при группировке.

+0

И это самый быстрый. –

+0

Да .. приятно .. спасибо .. upvote –

+0

«И это самый быстрый». - Вы делаете ставку! ;-) –

3

Как @PaulSpiegel, предложенный в комментариях, я думаю, что небольшое изменение в структуре таблицы сделает вашу жизнь намного проще.
Предлагаю вам изменить свой edited_id на 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 
+0

Звучит неплохо .. upvote .. Но вы знаете, [это] (http://stackoverflow.com/questions/39177757/how-can-i-select -последний-отредактированный-вариант-оф-пост) - мой полный вопрос. Как вы думаете, будет ли ваш подход работать на столе, который находится в этом вопросе? –

+0

@MartinAJ - да, он тоже должен работать для этого, я думаю, вам нужно добавить столбец 'type' во внутренний запрос, чтобы получить оба типа (оба для выбранных столбцов, которые будут использоваться в соединении, и к группе) –

+0

В вашей структуре таблицы мне нужно поместить идентификатор в столбец 'content_id', когда строка не будет отредактирована. Другими словами, как я могу вставить строку и установить значение «id» также как значение «content» в одно и то же время? –

Смежные вопросы