Увы я не пишу на мускуле, потому пример для MS SQL
но полагаю с минимальными правками он будет работать и на мускуле.
drop table if exists t1;
create table t1
(Id int primary key, Parent_Id int, code nvarchar(10), TextValue nvarchar(max));
-- Если у стаьи с разной версионностью есть набор полей (или одно поле, у меня это CODE)
-- Которые гарантированно уникальны, тогда все много проще
insert into t1(Id, Parent_Id, code, TextValue) values (1,0, 'Message', 'The variant');
insert into t1(Id, Parent_Id, code, TextValue) values (2,1, 'Message', 'The variant.');
insert into t1(Id, Parent_Id, code, TextValue) values (3,2, 'Message', 'Variant.');
insert into t1(Id, Parent_Id, code, TextValue) values (4,0, 'Letter', 'Hi dear Kat');
insert into t1(Id, Parent_Id, code, TextValue) values (5,4, 'Letter', 'Hi Kat');
-- запрос обычный вложенный
select * from t1 a
join (select code, max(Parent_Id) Parent_Id from t1 group by code )b
on a.code = b.code and a.Parent_Id = b.Parent_Id;
-- но если появляется такой "колобок" как описано ниже
-- у нас колобок с Id 6 и колобок с Id 8 это последнии
-- ревизии разных статей с одним кодом.
insert into t1(Id, Parent_Id, code, TextValue) values (6,0, 'Kolobok', 'K1');
insert into t1(Id, Parent_Id, code, TextValue) values (7,0, 'Kolobok', 'K2');
insert into t1(Id, Parent_Id, code, TextValue) values (8,7, 'Kolobok', 'K3');
-- тогда запрос выйдаст не красивый результат
select * from t1 a
join (select code, max(Parent_Id) Parent_Id from t1 group by code )b
on a.code = b.code and a.Parent_Id = b.Parent_Id;
-- нужно делать иерархический запрос, например такой.
with z (Kod, id, parent_id, code, TextValue) as
(
select Kod=a.id, a.id, a.parent_id, a.code, a.TextValue from t1 a where parent_id = 0
union all
select z.Kod, a.id, a.parent_id, a.code, a.TextValue from t1 a
join z on a.Parent_Id = z.id
)
select z.* from z join (select Kod, id = max(id) from z group by Kod ) x on z.Id = x.id;