2009-10-20 3 views
1

У меня есть база данных MySQL (созданный Wordpress), и это похоже на то, как это выглядит:Подсчитайте родительские слова в одном SQL-запросе?

ID parentID  otherStuff 
54 55   this is a test 
55 56   another test 
56 0   last test 

Что мне нужно сделать, это проверить, насколько глубоко вниз страницы. Я знаю, что когда он достигнет parentID 0, он закончен.

Я мог бы написать 3 запроса, а затем проверить, когда равно 0, но было бы более приятно, если это возможно только с одним запросом. Является ли это возможным? Как?

Вот пример:

  • ID: 56 имеет родителя 0 и имеет глубину 0. (теперь 1 запрос)
  • ID: 55 имеет родительский 56 затем 0 и имеет глубину 1. (Теперь 2 querys)
  • ID: 54 имеет родителя 55 затем 56, то 0 и имеет глубины 2. (в настоящее время 3 querys)

я решил его "неправильный путь" (с одним запросом каждого уровня глубины) здесь get_depth()

Проблема в том, что это рекурсивная функция, и для каждой глубины требуется еще один запрос.

+0

Иерархические запросы в MySQL: http://explainextended.com/2009/08/17/hierarchical-queries-in-mysql-varchar-keys/ –

+0

Список вложений и вложенных наборов в MySQL: http://explainextended.com/2009/09/29/adjacency-list-vs-nested-sets-mysql/ –

ответ

0

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

<?php $depth = count($post->ancestors); echo $depth; ?> 

Простой, но он работает.

Ваши решения по этой проблеме работают не только на Wordpress, если они работают. Должен ли я установить свое решение как правильное, что вы думаете?

+1

Помните, что post-> предки могут не всегда корректно устанавливаться. См. Https://core.trac.wordpress.org/ticket/10381 – Michael

0

Для этого потребуется петля какой-либо формы для обработки произвольной глубины.

Петля может быть в виде процедурного SQL (LOOP/LEAVE) или в вашем коде интерфейса, который вы написали. Внешний интерфейс будет медленнее из-за круглых поездок в базу данных.

General solutions for handling Hierarchical MySQL data

0

Если вы хотите запросить дерево в реляционной базе данных, использовать nested set для представления отношений. Это позволит вам использовать один запрос, чтобы найти глубину элемента, полный список предков, найти все связанные случаи и многое другое.

+2

Это wordpress DB. вероятно, не может произвольно изменить схему. –

+1

Он использует mysql, а не сервер sql. –

+0

@Byron Хороший улов; просто я неряшлив. –

0
WITH RECURSIVE depths(id, parentId, depth) AS (
    SELECT stuff.id, stuff.parentId, 0 FROM stuff WHERE parentId = 0 
    UNION 
    SELECT stuff.id, stuff.parentId, depths.depth + 1 
     FROM stuff INNER JOIN depths 
     ON stuff.parentId = depths.id 
) SELECT * FROM depths; 

Конечно, MySQL не поддерживает SQL-99-х WITH RECURSIVE, но можно определенно сделать то же самое итеративно. Возможно, вам стоит даже держать таблицу с глубиной или добавить столбец в существующую таблицу.

0

Тип таблицы, которую вы имеете, называется Adjacency List. В MySQL не возможно иметь произвольный запрос глубины в списке смежности.

Обычное излечение от этого (учитывая, что вы не хотите использовать вложенные наборы, и вы контролируете вашу схему db) заключается в том, чтобы хранить глубину узла как поле в строке узла (или хранить строку с разделителями который представляет собой путь к узлу). Если у вас нет контроля над структурой таблицы, лучше всего создать скрипт, который запрашивает до тех пор, пока он не достигнет parent_id = 0

1

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

CREATE FUNCTION get_nested_count(start INT) RETURN INT 
BEGIN 
    DECLARE count INT 0; 
    DECLARE current INT; 
    current = start; 
    DO 
     count = count + 1; 
     SELECT * FROM pages where "id"=current; 
     current = pages.parent 
    WHILE(pages.parent > 0 && pages.parent != start); 
    RETURN count; 
END 

Вторая проверка на время предотвращает круговой цикл (надеюсь: P)

0

Вы может сделать что-то подобное. Он не является полным, но это может дать вам представление о том, как решить вашу проблему с помощью общих выражений таблицы в SQL Server.

WITH [CTE] 
    AS (SELECT * FROM TieredTable t1 
      UNION ALL 
     SELECT t1.* FROM [CTE] cte, TieredTable t1 
     WHERE t1.[Parent_Id] = cte.[Id]) 
SELECT COUNT(*) AS cnt, id 
    FROM [CTE] 
WHERE parent_id <> 0 
GROUP BY id 

Вот стол;

CREATE TABLE [dbo].[TieredTable](
    [id] [int] NULL, 
    [parent_id] [int] NULL, 
    [stuff] [varchar](50) NULL 
) 

id  pid  stuff 
10 0 One 
20 10 Two 
30 20 Three 
0

Этот запрос возвратит вас уровень глубины для любого заданного узла:

SELECT COUNT(*) 
FROM (
     SELECT id, 
       @r := 
       (
       SELECT parent 
       FROM mytable 
       WHERE id = @r 
         AND id <> 0 
       ) AS _parent 
     FROM (
       SELECT @r := 56 
       ) vars, 
       mytable 
     WHERE @r IS NOT NULL 
     ) q 
WHERE _parent IS NOT NULL; 

Заменить @r := 56 с узлом id вы хотите.

Смежные вопросы