2014-10-17 2 views
0

다음 SQL을 사용하여 계층 적 데이터를 생성하고 자식이 정렬 순서 ID 값별로 정렬되도록하는 방법을 고민하고 있습니다. 어떻게 감사 할 지에 대한 조언. 이것은 내 SQL이 아니며, 내가 수정 한 OpenCart의 Category 목록 페이지에서 가져온 것입니다. 정렬 순서를 몇 군데에 추가하려고 시도했지만 아무런 차이가없는 것 같습니다. 내가 원하는 출력을 보여입니다 트리의 각 하위 집합이 sort_order 열을 기준으로 개별적으로 주문되므로 Index의 정렬 순서가 Sub1, Sub2 또는 Sub3과에 영향을주지 않습니다열 값을 기준으로 계층 적 SQL 행 정렬

| PAGE_ID |      NAME | PARENT_ID | SORT_ORDER | 
|---------|----------------------------|-----------|------------| 
|  75 |      Index4 |   0 |   -7 | 
|  60 |      Index |   0 |   0 | 
|  68 |    Index > Sub6 |  60 |   -6 | 
|  61 |    Index > Sub1 |  60 |   1 | 
|  65 | Index > Sub1 > SubSub2 |  61 |   4 | 
|  64 | Index > Sub1 > SubSub1 |  61 |   6 | 
|  67 |    Index > Sub5 |  60 |   1 | 
|  62 |    Index > Sub2 |  60 |   2 | 
|  63 |    Index > Sub3 |  60 |   5 | 
|  69 | Index > Sub3 > SubSub3 |  63 |   1 | 
|  71 | Index > Sub3 > SubSub5 |  63 |   2 | 
|  72 | Index > Sub3 > SubSub4 |  63 |   5 | 
|  70 | Index > Sub3 > SubSub6 |  63 |   9 | 
|  66 |    Index > Sub4 |  60 |   7 | 
|  74 |      Index3 |   0 |   1 | 
|  73 |      Index2 |   0 |   4 | 

공지 사항 그 중 어느 것도 SubSub1, SubSub2 또는 SubSub3

Here's the SQL Fiddle

DROP TABLE IF EXISTS `oc_page`; 
CREATE TABLE `oc_page` (
    `page_id` int(11) NOT NULL AUTO_INCREMENT, 
    `parent_id` int(11) NOT NULL DEFAULT '0', 
    `sort_order` int(3) NOT NULL DEFAULT '0', 
    `status` tinyint(1) NOT NULL, 
    `date_added` datetime NOT NULL, 
    `date_modified` datetime NOT NULL, 
    PRIMARY KEY (`page_id`), 
    KEY `parent_id` (`parent_id`) 
) ENGINE=MyISAM AUTO_INCREMENT=66 DEFAULT CHARSET=utf8; 

BEGIN; 
INSERT INTO `oc_page` VALUES ('60', '0', '0', '1', '2014-10-16 02:49:41', '2014-10-17 02:03:15'), ('61', '60', '1', '1', '2014-10-17 02:03:02', '2014-10-17 03:17:20'), ('62', '60', '2', '1', '2014-10-17 02:18:59', '2014-10-17 03:16:20'), ('63', '60', '3', '1', '2014-10-17 02:23:27', '2014-10-17 03:16:49'), ('64', '61', '6', '1', '2014-10-17 03:17:49', '2014-10-17 03:17:58'), ('65', '61', '4', '1', '2014-10-17 03:18:36', '2014-10-17 03:18:36'); 
COMMIT; 

DROP TABLE IF EXISTS `oc_page_description`; 
CREATE TABLE `oc_page_description` (
    `page_id` int(11) NOT NULL, 
    `language_id` int(11) NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `description` text NOT NULL, 
    `meta_title` varchar(255) NOT NULL, 
    `meta_description` varchar(255) NOT NULL, 
    `meta_keyword` varchar(255) NOT NULL, 
    PRIMARY KEY (`page_id`,`language_id`), 
    KEY `name` (`name`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

BEGIN; 
INSERT INTO `oc_page_description` VALUES ('60', '1', 'Index', '<p>Test</p>', 'Test', '', ''), ('61', '1', 'Sub1', 'Sub1', 'Sub1', '', ''), ('64', '1', 'SubSub1', 'SubSub1', 'SubSub1', '', ''), ('65', '1', 'SubSub2', 'SubSub2', 'SubSub2', '', ''), ('62', '1', 'Sub2', 'Sub2', 'Sub2', '', ''), ('63', '1', 'Sub3', 'Sub3', 'Sub3', '', ''); 
COMMIT; 

DROP TABLE IF EXISTS `oc_page_path`; 
CREATE TABLE `oc_page_path` (
    `page_id` int(11) NOT NULL, 
    `path_id` int(11) NOT NULL, 
    `level` int(11) NOT NULL, 
    PRIMARY KEY (`page_id`,`path_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

BEGIN; 
INSERT INTO `oc_page_path` VALUES ('60', '60', '0'), ('61', '61', '1'), ('61', '60', '0'), ('62', '62', '1'), ('62', '60', '0'), ('63', '63', '1'), ('63', '60', '0'), ('64', '64', '2'), ('64', '60', '0'), ('64', '61', '1'), ('65', '60', '0'), ('65', '61', '1'), ('65', '65', '2'); 
COMMIT; 

DROP TABLE IF EXISTS `oc_page_to_store`; 
CREATE TABLE `oc_page_to_store` (
    `page_id` int(11) NOT NULL, 
    `store_id` int(11) NOT NULL, 
    PRIMARY KEY (`page_id`,`store_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

BEGIN; 
INSERT INTO `oc_page_to_store` VALUES ('60', '0'), ('61', '0'), ('62', '0'), ('63', '0'), ('64', '0'), ('65', '0'); 
COMMIT; 
에 영향을주지 않습니다

검색어 1 :

Results

SELECT pp.page_id AS page_id, 
     GROUP_CONCAT(pd1.name 
        ORDER BY pp.level SEPARATOR ' > ') AS name, 
     p1.parent_id, 
     p1.sort_order 
FROM oc_page_path pp 
LEFT JOIN oc_page p1 ON (pp.page_id = p1.page_id) 
LEFT JOIN oc_page p2 ON (pp.path_id = p2.page_id) 
LEFT JOIN oc_page_description pd1 ON (pp.path_id = pd1.page_id) 
LEFT JOIN oc_page_description pd2 ON (pp.page_id = pd2.page_id) 
WHERE pd1.language_id = '1' 
    AND pd2.language_id = '1' 
GROUP BY pp.page_id 
ORDER BY name ASC LIMIT 0,20 
:

참고 :이 좀 더 질문을 명확히하기 위해 추가 한 더미 데이터입니다. 바이올린은 훨씬 적은 데이터

표시됩니다
| PAGE_ID |      NAME | PARENT_ID | SORT_ORDER | 
|---------|----------------------------|-----------|------------| 
|  60 |      Index |   0 |   0 | 
|  61 |    Index > Sub1 |  60 |   1 | 
|  64 | Index > Sub1 > SubSub1 |  61 |   6 | 
|  65 | Index > Sub1 > SubSub2 |  61 |   4 | 
|  62 |    Index > Sub2 |  60 |   2 | 
|  63 |    Index > Sub3 |  60 |   5 | 
|  69 | Index > Sub3 > SubSub3 |  63 |   1 | 
|  70 | Index > Sub3 > SubSub6 |  63 |   9 | 
|  71 | Index > Sub3 > SubSub5 |  63 |   2 | 
|  72 | Index > Sub3 > SubSub4 |  63 |   5 | 
|  66 |    Index > Sub4 |  60 |   7 | 
|  67 |    Index > Sub5 |  60 |   1 | 
|  68 |    Index > Sub6 |  60 |   -6 | 
|  73 |      Index2 |   0 |   4 | 
|  74 |      Index3 |   0 |   1 | 
|  75 |      Index4 |   0 |   -7 | 
당신은 단순히 내부 ORDER에서 디스플레이 ORDER 이혼 하위 쿼리를 사용할 수 있습니다
+0

가 나는 downvote에 문제가있어,하지만 난 할 사람들은 적어도 이렇게하기 전에 무엇이 개선되어야하는지에 대해 논평 할 것입니다. –

답변

1

:

SELECT * 
FROM (
     SELECT pp.page_id AS page_id, 
      GROUP_CONCAT(pd1.name 
          ORDER BY pp.level SEPARATOR ' > ') AS name, 
      p1.parent_id, 
      p1.sort_order 
     FROM oc_page_path pp 
     LEFT JOIN oc_page p1 ON (pp.page_id = p1.page_id) 
     LEFT JOIN oc_page p2 ON (pp.path_id = p2.page_id) 
     LEFT JOIN oc_page_description pd1 ON (pp.path_id = pd1.page_id) 
     LEFT JOIN oc_page_description pd2 ON (pp.page_id = pd2.page_id) 
     WHERE pd1.language_id = '1' 
     AND pd2.language_id = '1' 
     GROUP BY pp.page_id 
     ORDER BY name ASC LIMIT 0,20 
     ) sub 
ORDER BY Sort_Order 

데모 : SQL Fiddle

참고 : 나는 당신이 필요로하는 가정을 내부는 LIMIT으로 인해 ORDER BY인데, 그렇지 않으면 단지 ORDER BY Sort_Order 일 수 있기 때문입니다. 내가 제대로 질문을 이해한다면

+0

감사합니다. 그러나 이것이 효과가 있다고 생각하지 않습니다. 기본적으로 계층 구조의 각 수준은'sort_order'와'parent_id'에 기초하여 정렬 될 필요가 있습니다. 더 좋은 예를 들어주기 위해 질문을 업데이트했습니다. 또한 여기의 한계는 무의미합니다 –

+0

흠, 주문 논리를 따르지 않을지 모르겠지만 원하는 것과 현재의 유일한 차이는 65와 64가 전환되었지만 이유는 무엇입니까? –

+0

그걸 알아 내려고했는데 정렬 필드를 얻기 위해 일부 조건부 집계를 사용해야하는 상황이 될 수 있지만 그룹화되지 않은 모든 관련 필드를 살펴보면 원하는 순서 뒤의 추론을 볼 수 없습니다. 조금만 더 확장하면 얻을 수있을 것이라고 확신합니다. –

0

당신은 SORT_ORDER에 의해 그 다음 제 순서에 따라 이름, 순서의 마지막 부분의 절단 할 수 있습니다

select page_id, parent_id, sort_order, name 
    , substr(name, 1, length(name) - locate(' > ', reverse(name))) as path 
from (
    SELECT pp.page_id AS page_id 
     , GROUP_CONCAT(pd1.name ORDER BY pp.level SEPARATOR ' > ') AS name 
     , p1.parent_id, p1.sort_order 
    FROM oc_page_path pp 
    LEFT JOIN oc_page p1 
     ON pp.page_id = p1.page_id 
    LEFT JOIN oc_page p2 
     ON pp.path_id = p2.page_id 
    LEFT JOIN oc_page_description pd1 
     ON pp.path_id = pd1.page_id 
    LEFT JOIN oc_page_description pd2 
     ON pp.page_id = pd2.page_id ' 
    WHERE pd1.language_id = '1' 
     AND pd2.language_id = '1' 
    GROUP BY pp.page_id, p1.parent_id, p1.sort_order 
) as t 
order by path, sort_order; 

+---------+-----------+------------+----------------------------+-------------------+ 
| page_id | parent_id | sort_order | name      | path    | 
+---------+-----------+------------+----------------------------+-------------------+ 
|  60 |   0 |   0 | Index      | Index    | 
|  61 |  60 |   1 | Index > Sub1    | Index >   | 
|  62 |  60 |   2 | Index > Sub2    | Index >   | 
|  63 |  60 |   3 | Index > Sub3    | Index >   | 
|  65 |  61 |   4 | Index > Sub1 > SubSub2 | Index > Sub1 > | 
|  64 |  61 |   6 | Index > Sub1 > SubSub1 | Index > Sub1 > | 
+---------+-----------+------------+----------------------------+-------------------+ 
+0

안녕하세요 Lennart.제가 작성한 업데이트와 Goat CO.의 답변에 대한 감사를보십시오. 감사합니다. –

+0

좋습니다. 형제가 정렬 순서에 따라 정렬되는 Depth First Search (DFS)가 필요합니다. 그게 가능한지 모르겠다. (모델을 바꾸지 않고). 모델을 기준으로 DFS를 얻으려면 일반적으로 정식 이름이 필요합니다. 그러면 부모가있는 부모가 바로 뒤에 정렬됩니다. 하지만 정렬 순서는 아무런 효과가 없습니다. 또한 각 레벨의 길이가 동일한 지 확인하십시오. 그렇지 않으면 정렬이 중단됩니다. 도와 드릴 수 없어서 죄송합니다. – Lennart

+0

어쨌든 Lennart에게 감사드립니다. 시간을내어 도와 주려고합니다. –