Если это для SQL Server 2005 или более поздней версии, вы можете сделать:
SELECT t.top_level_cat_id, t.category_id, t.post_id, t.post_date
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY top_level.cat_id ORDER BY p.post_id) AS row_num,
top_level.cat_id AS top_level_cat_id,
child_category.cat_id AS category_id,
p.post_id,
p.post_date
FROM
Post p
INNER JOIN Category AS child_category
ON child_category.cat_id = p.cat_id
INNER JOIN Category AS top_level
ON top_level.cat_id = child_category.cat_parent
) AS t
WHERE t.row_num <= 15
Вот T-SQL, который я использовал для создания тестовых таблиц:
CREATE TABLE Category (cat_id INT, cat_parent INT);
--top level
INSERT INTO Category VALUES(1, 0);
INSERT INTO Category VALUES(2, 0);
-- child categories
INSERT INTO Category VALUES(3, 1);
INSERT INTO Category VALUES(4, 1);
INSERT INTO Category VALUES(5, 2);
CREATE TABLE Post(post_id INT, cat_id INT, post_date DATETIME);
INSERT INTO Post VALUES(1, 3, GETDATE());
INSERT INTO Post VALUES(2, 3, GETDATE());
INSERT INTO Post VALUES(3, 3, GETDATE());
INSERT INTO Post VALUES(4, 3, GETDATE());
INSERT INTO Post VALUES(5, 3, GETDATE());
INSERT INTO Post VALUES(6, 3, GETDATE());
INSERT INTO Post VALUES(7, 3, GETDATE());
INSERT INTO Post VALUES(8, 3, GETDATE());
INSERT INTO Post VALUES(9, 3, GETDATE());
INSERT INTO Post VALUES(10, 3, GETDATE());
INSERT INTO Post VALUES(11, 3, GETDATE());
INSERT INTO Post VALUES(12, 3, GETDATE());
INSERT INTO Post VALUES(13, 3, GETDATE());
INSERT INTO Post VALUES(14, 3, GETDATE());
INSERT INTO Post VALUES(15, 3, GETDATE());
-- these records won't appear
INSERT INTO Post VALUES(16, 3, GETDATE());
INSERT INTO Post VALUES(17, 4, GETDATE());
INSERT INTO Post VALUES(18, 4, GETDATE());
INSERT INTO Post VALUES(19, 5, GETDATE());
INSERT INTO Post VALUES(20, 5, GETDATE());