Как получить статьи определенной категории и ее детей?

Я разрабатываю систему статей, в которой используются категории и дочерние категории.

В принципе, если категория имеет значение parent_id, это дочерний элемент этой категории.

Я хотел бы иметь возможность получать последние статьи из категории и статей из своих дочерних категорий.

Например: у меня есть категория под названием "Игровые статьи" и несколько дочерних категорий под названием Xbox, PlayStation, Nintendo и ПК. Моя система позволяет размещать статьи в родительских категориях, таких как игровые статьи, а также в дочерних категориях.

Таким образом, это должно включать статьи, которые находятся либо в родительской категории, либо в дочерних категориях этого родителя.

CREATE TABLE IF NOT EXISTS `articles` (
  `article_id` int(15) NOT NULL AUTO_INCREMENT,
  `author_id` int(15) NOT NULL,
  `category_id` int(15) NOT NULL,
  `modification_id` int(15) NOT NULL,
  `title` varchar(125) NOT NULL,
  `content` text NOT NULL,
  `date_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `status` tinyint(1) NOT NULL,
  `attachment_id` int(15) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `article_categories` (
  `category_id` int(15) NOT NULL AUTO_INCREMENT,
  `parent_id` int(15) NOT NULL,
  `title` varchar(50) NOT NULL,
  `description` text NOT NULL,
  `attachment_id` text NOT NULL,
  `enable_comments` tinyint(1) NOT NULL,
  `enable_ratings` tinyint(1) NOT NULL,
  PRIMARY KEY (`category_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

Запрос, который у меня есть до сих пор...

SELECT article_id, category_id
FROM articles
WHERE category_id = 1
ORDER BY article_id DESC
LIMIT 10

Конечно, это получает только статьи под этой категорией, а не как дочерние категории категории, так и категории.

Ответ 1

По мере того, как ваша структура таблицы стоит, этот запрос будет работать, если предполагается только один уровень вложенности (т.е. дети сами не имеют детей):

SELECT a.*
FROM articles a
JOIN article_categories ac ON a.category_id = ac.category_id
WHERE 1 IN (a.category_id, ac.parent_id)
ORDER BY a.article_id DESC
LIMIT 10

Обратите внимание на стиль "reverse" IN, чтобы аккуратно захватить то, что эффективно является OR.

Если ваша вложенность глубже, просто добавьте другое соединение для каждого уровня, например, если у вас есть до 4 уровней (на 2 больше, чем выше):

SELECT a.*
FROM articles a
JOIN article_categories ac1 ON a.category_id = ac1.category_id
LEFT JOIN article_categories ac2 ON ac1.parent_id = ac2.category_id
LEFT JOIN article_categories ac3 ON ac2.parent_id = ac3.category_id
WHERE 1 IN (a.category_id, ac1.parent_id, ac2.parent_id, ac3.parent_id
ORDER BY a.article_id DESC
LIMIT 10

Во втором случае использование левых объединений необходимо для возврата статей, которые не имеют так много уровней выше.

Ответ 2

В этой структуре она невозможна в одном запросе. (Я предполагаю, что существует много уровней категорий)

Вы можете:

  • рекурсивно искать дочерние категории (например, в php), а затем

    SELECT * FROM articles WHERE category_id IN ($ categories);

  • изменить структуру db и использовать древовидную структуру try: Вложенная модель набора в статье: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

  • добавить новую таблицу в таблицу категорий и сохранить полный путь к категории, например:

    категория 1- > 2, category_path 1,2 категория 1- > 2- > 3, category_path 1,2,3 категория 1- > 4, новая категория_path 1,4

Если вы ищете все данные категории 1 и детей, попробуйте:

SELECT 
    a.* 
FROM articles a
INNER JOIN categories c
    ON a.category_id = c.category_id
WHERE c.category_path LIKE '1,%'

Ответ 3

Насколько я понимаю, вы хотите получить все статьи от ребенка категории, если это правильно, попробуйте это:

SELECT a.article_id, a.category_id FROM articles as a, article_categories c  WHERE a.category_id = c.category_id AND c.parent_id = (SELECT c.parent_id WHERE c.category_id = 1) ORDER BY article_id DESC LIMIT 10

Если это не то, что вы хотели, прокомментируйте это, я постараюсь ответить вам.