SQL иерархический документ с вложенными наборами - PullRequest
1 голос
/ 04 июня 2019

Я пытаюсь создать таблицы и операторы SQL для моего сценария. Я использую mySQL.

У меня есть стандартная иерархическая структура для документов, но структура конкретного документа для клиента может отличаться от стандартной структуры.

Моя таблица, в которой сохраняются все абзацы и стандартная структура, выглядит следующим образом:

CREATE TABLE paragraphs (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  title TEXT CHARACTER SET utf8 COLLATE utf8_german2_ci NOT NULL,
  lft INT NOT NULL,
  rgt INT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

и вставки, например:

INSERT INTO paragraphs (id,title,lft,rgt)VALUES(1,'Heading 1',1,2);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(2,'Heading 2',3,4);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(3,'Heading 3',5,6);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(4,'Heading 4',7,8);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(5,'Heading 5',9,16);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(6,'Heading 5.1',10,11);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(7,'Heading 5.2',12,13);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(8,'Heading 5.3',14,15);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(9,'Heading 6',17,18);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(10,'Heading 7',19,20);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(11,'Heading 8',21,42);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(12,'Heading 8.1',22,31);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(13,'Heading 8.1.1',23,24);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(14,'Heading 8.1.2',25,26);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(15,'Heading 8.1.3',27,28);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(16,'Heading 8.1.4',29,30);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(17,'Heading 8.2',32,33);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(18,'Heading 8.3',34,35);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(19,'Heading 8.4',36,37);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(20,'Heading 8.4.1',38,39);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(21,'Heading 8.4.2',40,41);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(22,'Heading 9',43,44);
INSERT INTO paragraphs (id,title,lft,rgt)VALUES(23,'Heading 10',45,46);

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

CREATE TABLE document (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    client INT NOT NULL,
    paragraph INT NOT NULL,
    lft INT NOT NULL,
    rgt INT NOT NULL,
    FOREIGN KEY (paragraph) REFERENCES paragraphs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

и для этой таблицы приведен пример вставки:

INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,1,1,2);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,11,3,16);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,12,4,9);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,15,5,6);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,16,7,8);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,17,10,11);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,18,12,13);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,19,14,15);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(1,23,17,18);

INSERT INTO document (client,paragraph,lft,rgt)VALUES(2,9,1,2);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(2,21,3,4);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(2,22,5,6);

INSERT INTO document (client,paragraph,lft,rgt)VALUES(3,5,1,6);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(3,6,2,3);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(3,7,4,5);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(3,11,7,10);
INSERT INTO document (client,paragraph,lft,rgt)VALUES(3,16,8,9);

Теперь я пытаюсь получить все отсортированные абзацы определенного документа, и он работает со следующим запросом:

SELECT DISTINCT para.title
FROM document AS node,
document AS parent
INNER JOIN paragraphs AS para ON para.id = parent.paragraph
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.client = 1
ORDER BY node.lft;

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

SELECT para.title, (COUNT(parent.id) - 1) AS depth
FROM document AS node,
document AS parent
INNER JOIN paragraphs AS para ON para.id = parent.paragraph
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND parent.client = 1
GROUP BY para.title
ORDER BY node.lft;

Вы можете мне помочь? :)

...