DISTINCT работи върху всички колони в SELECT, така че вие избирате всичко, той ще върне всеки отделен ред, а не само отделните публикации. За да заобиколите това, можете просто да ИЗБЕРЕТЕ данните от таблицата с публикации и след това да ги РАЗЛИЧИТЕ, т.е.
SELECT DISTINCT posts.*
Но също така казахте, че бихте искали и информацията за публикациите и котките, ако е възможно. Един от начините да направите това и да запазите един ред на публикация е да използвате GROUP_CONCAT така че вашата заявка може да завърши нещо подобно.
SELECT
posts.*,
GROUP_CONCAT(cats.id SEPARATOR ',') as catsList,
GROUP_CONCAT(tags.id SEPARATOR ',') as tagsList
FROM posts
INNER JOIN termRelations ON ( posts.id = termRelations.postId )
LEFT JOIN cats ON ( termRelations.termId = cats.id AND termRelations.termTypeId = 1 AND cats.id =5 )
LEFT JOIN tags ON ( termRelations.termId = tags.id AND termRelations.termTypeId = 0 AND
(tags.id =2
OR tags.id =1)
)
GROUP BY posts.id
LIMIT 0 , 30
Направих няколко други промени в първоначалната ви заявка, като например промяна на първото присъединяване към INNER JOIN и добавяне на филтри за котки/тагове към условията JOIN за съответните таблици.
п.с. когато кажете, че имате отделни таблици за котки и тагове, за да ускорите генерирането на списъци, може да откриете, че една таблица, която е правилно индексирана, ще бъде също толкова бърза и също така ще опрости кода ви.