Я не большой специалист по базам данных, но, кажется, реализация сильно зависит от количества новостей, которое вы предвидите.
Если их будет мало (до 1-5 тысяч, скажем) то можно обойтись 2 запросами:
например, сначала выбрать новости для первого блока (ORDER BY date DESC LIMIT 4)
вторым запросом выбрать все новости ORDER BY date DESC (можно добавить WHERE id NOT IN(тут idшники из первого запроса))
создадим массив $blocks и вложенные массивы $blocks["$category_id"] = array(); (по количеству нужных нам блоков-категорий)
заполнить блоки:
n = 5;
foreach ($news as $news_item) {
$category_id = $news_item['category_id'];
foreach ($blocks as $block_category_id=>$block_news)
{
if ($category_id == $block_category_id && count($block_news) < n)
{
$block_news[] = $news_item;
break;
}
}
}
(код не проверял, возможны ошибки-опечатки)
Но, я предполагаю, что на большой количестве новостей подобный подход даст существенную нагрузку, и, возможно, проще было бы сделать 6 простых SELECT WHERE category_id = :my_category_id LIMIT :n.
Советую все это проверить и не использовать как есть, попробовать разные варианты (ну или подождать ответ кого-нибудь, кто имеет лучший скилл в sql :) )