【问题标题】:MYSQL: select parent sorted alphabetically grouped with children sorted alphabeticallyMYSQL:选择按字母顺序排序的父级和按字母顺序排序的子级
【发布时间】:2017-07-26 02:00:06
【问题描述】:

我制作了一个简单的表格来了解父子关系,但我似乎没有得到正确的结果。我要排序

  1. 按“姓名”字段的字母顺序排列,仅限没有父母的人 (parent_id==0)
  2. 但是,只要有父级的子行,它们应该打印在父级之后,也按名称的字母顺序排序。

示例表:

================================================ ==============

CREATE TABLE IF NOT EXISTS `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) NOT NULL DEFAULT '0',
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;

--
-- Dumping data for table `test`
--

INSERT INTO `test` (`id`, `parent_id`, `name`) VALUES
(1, 4, 'Zorg'),
(2, 0, 'Woordolack'),
(3, 4, 'Akriller'),
(4, 0, 'Metabrusher'),
(5, 2, 'Intersplitter'),
(6, 0, 'Beaverbrain'),
(7, 4, 'Torgeoruos'),
(8, 2, 'Deptezaurus');

================================================ ==============

这是我想使用 PHP 输出到 Web 浏览器的内容:

 Beaverbrain
 Metabrusher
 -> Akriller
 -> Torgeoruos
 -> Zorg
 Woordolack
 -> Deptezaurus
 -> Intersplitter

================================================ ==============

我应该说这是一个示例表,只是为了展示这个想法,因此可以通过任何方式对其进行修改以获得正确的结果。

【问题讨论】:

    标签: php mysql database sorting


    【解决方案1】:

    你可以试试这个查询

    SELECT IF(child = '',parent,CONCAT('->',child)) as value 
    FROM
        (SELECT parent.name as parent,child.name as child
         FROM test parent 
           INNER JOIN 
           (SELECT id,parent_id,name FROM test 
            UNION 
            SELECT null,id,'' FROM test
            WHERE parent_id = 0)child
         WHERE parent.parent_id = 0
         AND child.parent_id = parent.id
         ORDER BY parent,child
         )parent_child
    

    sqlFiddle

    查询所做的是 INNER JOIN 测试与 test 并找出哪些是父母和孩子。内部 UNION SELECT null,id,'' FROM test WHERE parent_id = 0 创建一个空的 child(ren) 用于显示目的。然后外部 SELECT 看看孩子是否是 '' 它打印出父母,否则它在孩子前面连接 ->。这样你就可以得到你想要的结果。

    以下版本可能会快一点。因为我们将只创建具有 NULL 子项的父项,而不是使用子项作为 INNER JOIN 的一部分(上图)。

    SELECT IF(child IS NULL,parent,CONCAT('->',child)) as value 
    FROM
     (SELECT parent.name as parent,child.name as child
        FROM test parent 
       INNER JOIN test child ON child.parent_id = parent.id
       WHERE parent.parent_id = 0
      UNION
      SELECT test.name as parent,NULL as child    #This creates a NULL child row
        FROM test WHERE test.parent_id = 0        #for parent display purpose
      ORDER BY parent,child
     )parent_child
    

    sqlFiddle

    不过,我会改用下面的查询,并在 PHP 中检查 isParent 标志是 1 还是 0,然后显示相应的字段。

    SELECT 0 as isParent,parent.name as parent,child.name as child,
           parent.id as parentId,child.id as childId
      FROM test parent 
     INNER JOIN test child ON child.parent_id = parent.id
     WHERE parent.parent_id = 0
    UNION
    SELECT 1 as isParent,test.name as parent,NULL as child,
           test.id as parentId,NULL as childId
      FROM test WHERE test.parent_id = 0       
    ORDER BY parent,child
    

    sqlFiddle

    【讨论】:

    • 哇,它以某种方式工作!这是学习 MYSQL 的一个非常酷的例子(虽然我很难理解)。但是如果真实表有数千条记录并且还左连接其他表以获取更多数据,它将如何影响性能呢?
    • 性能方面我不确定,取决于索引,但直到你实际在实际数据上运行它才会知道。要理解它,您可以尝试选择(通过突出显示)仅内部单个选择并在 sqlfiddle 上运行它们,您将看到数据返回并且您会理解。一旦你掌握了它就很简单了。
    • 我用不同的版本更新了我的答案,可能会更快更容易理解。
    • 这个例子对于学习来说很有趣,但是在现实生活中,当连接额外的表并且需要额外的值时,查询变得非常复杂并且可能需要大量的服务器资源。例如,如果我们需要额外获取更多的值,例如id,它应该是这样的: SELECT IF(child IS NULL,parent,CONCAT('->',child)) as value, IF(child IS NULL,parent .id,child.id) 作为 value1 等,这使它变得更加复杂。我想也许在 MYSQL 中进行一种简单的排序并在 PHP 中对输出进行样式化会更好?
    • 更新我的答案以包含一个版本,您可以在 PHP 中检查 isParent 标志并根据此标志显示适当的字段。
    【解决方案2】:

    试试这个解决方案:

    SELECT
        A.id,
        A.name
    FROM 
        `test` AS A LEFT JOIN `test` AS B ON A.`parent_id` = B.`id`
    GROUP BY
        A.`id`
    ORDER BY
        IFNULL(B.`name`, A.`name`), 
        COALESCE(A.`parent_id`, A.`id`), 
        A.`parent_id` != 0, 
        A.`name`;
    

    【讨论】:

      【解决方案3】:

      在 PHP 中使用几个简单的查询,

          $r1 = $db->query("select * from test where parent_id = 0 order by name asc") or die('err in q1');
          while($arr1 = $r1->fetch_assoc()){
                  $parent = $arr1['name'];
                  $parent_id = $arr1['id'];
                  echo $parent
                  $r2 = $db->query("select * from test where parent_id = $parent order by name asc") or die('err in q2');
                  while($arr2 = $r2->fetch_assoc()){
                       $child = $arr2['name'];
                       echo $child."<br />";
                  }
          }
      

      【讨论】:

      • 是的,这是一种简单明了的方法,但我不使用它,因为如果表有数百个父表,则第二个查询将执行数百次仅生成一页。如果用户每秒多次请求此页面......这将产生真正的性能问题。
      【解决方案4】:

      在管理分层数据时,您可以改用简单的 PHP 递归函数,

       function DisplayTree( $parent , $depth)     {                                                                                                    
          $sql = $this->db->query("SELECT id,name FROM '$table' WHERE parent_id = '$parent'");
      
            foreach($sql->result() as $field ) {  
              print "<fieldset style=\"margin-left:$depth%; width:300px\">";  
                  print $field->name;
              print "</fieldset>";
      
              $this->DisplayTree( $field->code , $depth+8 );           
           }  
      
         }  
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        相关资源
        最近更新 更多