【问题标题】:Hierarchy data in MySQL to PHP multidimensional arrayMySQL中的层次结构数据到PHP多维数组
【发布时间】:2013-11-05 10:24:48
【问题描述】:

只是为了学习 SQL,我想用一个简单的父子创建一个层次结构。就像堆栈溢出徽章(父母:问题徽章,孩子:利他主义者)。

这是我的 sql:

SELECT *
FROM (`badge_types`)
LEFT JOIN `badges` ON `badges`.`badge_type` = `badge_types`.`badge_type_id`

这是我得到的:

(
    [0] => stdClass Object
        (
            [badge_type_id] => 2
            [badge_type_title] => Participation Badges
            [badge_type_description] => Badges earning by participating in various areas of the site.
            [badge_type_order] => 2
            [badge_id] => 1
            [badge_name] => Autobiographer
            [badge_level] => 3
            [badge_requirement] => Completed all user profile fields
            [badge_type] => 2
            [badge_order] => 1
            [badge_sites] => 0
        )

    [1] => stdClass Object
        (
            [badge_type_id] => 1
            [badge_type_title] => Experience Badges
            [badge_type_description] => Badges earned by amount of experience gain throughout the site.
            [badge_type_order] => 1
            [badge_id] => 2
            [badge_name] => Apprentice
            [badge_level] => 3
            [badge_requirement] => Achieved 500 experience
            [badge_type] => 1
            [badge_order] => 1
            [badge_sites] => 0
        )

)

我怎样才能把它变成:

array(
    array(
        [badge_type_id] => 2
        [badge_type_title] => Participation Badges
        [badge_type_description] => Badges earning by participating in various areas of the site.
        [badge_type_order] => 2
        [badges] => array(
            array(
                [badge_id] => 1
                [badge_name] => Autobiographer
                [badge_level] => 3
                [badge_requirement] => Completed all user profile fields
                [badge_type] => 2
                [badge_order] => 1
                [badge_sites] => 0
            ),
            array(
                [badge_id] => 2
                [badge_name] => Example 2
                [badge_level] => 3
                [badge_requirement] => blah bla
                [badge_type] => 2
                [badge_order] => 1
                [badge_sites] => 0
            )
        )
    ),
    array(
        [badge_type_id] => 1
        [badge_type_title] => Experience Badges
        [badge_type_description] => Badges earned by amount of experience gain throughout the site.
        [badge_type_order] => 1
        [badges] => array(
            array(
                [badge_id] => 2
                [badge_name] => Apprentice
                [badge_level] => 3
                [badge_requirement] => Achieved 500 experience
                [badge_type] => 1
                [badge_order] => 1
                [badge_sites] => 0
            ),
            array(
                [badge_id] => 2
                [badge_name] => Example 2
                [badge_level] => 3
                [badge_requirement] => Achieved 1000 experience
                [badge_type] => 1
                [badge_order] => 1
                [badge_sites] => 0
            )
        )
    )
)

我可以使用多个 MySQL 查询来做到这一点,但如果可能的话,我只想使用一个查询?

【问题讨论】:

  • 使用与所选数据量成比例的 SQL 查询数量是非常糟糕的做法!您应该使用您的单个查询并根据您的需要调整它的结果。
  • 我希望有一个 php 解决方案,也许我应该编辑我的问题
  • 好的,我将编辑我的答案并提供我的 PHP 解决方案完整代码
  • 添加了可能的 PHP 解决方案示例。在这里你可以在线测试 - codepad.org/EqlkVYXV

标签: php mysql sql multidimensional-array hierarchical-data


【解决方案1】:

使用 SQL 查询无法实现这一点,因为(由于关系模型性质)SQL 查询将始终返回“平面”结果集而没有任何嵌套(很少有例外是供应商 SQL 扩展,其目标是生成 XML 输出等,但 MySQL 没有这样的扩展)。

如果您想从 SQL 结果集中获取嵌套数组,您必须使用 PHP 代码对其进行后处理。这段代码可以像数组上的分组循环一样组织(用 SQL 预排序),每次“内部”表的键发生变化时都会启动新组。这可以在 PHP 中以相当通用的方式完成,因此您可以编写一个这样的函数来后处理许多 SQL 查询(给它适当的参数)。

ADDITION下面是这样一个函数:

function groupnest( $data, $groupkey, $nestname, $innerkey ) {
  $outer0 = array();
  $group = array(); $nested = array();

  foreach( $data as $row ) {
    $outer = array();
    while( list($k,$v) = each($row) ) {
      if( $k==$innerkey ) break;
      $outer[$k] = $v;
    }

    $inner = array( $innerkey => $v );
    while( list($k,$v) = each($row) ) {
      if( $k==$innerkey ) break;
      $inner[$k] = $v;
    }

    if( count($outer0) and $outer[$groupkey]!=$outer0[$groupkey] ) {
      $outer0[$nestname] = $group;
      $nested[] = $outer0;
      $group = array();
    }
    $outer0 = $outer;

    $group[] = $inner;
  }
  $outer[$nestname] = $group;
  $nested[] = $outer;

  return $nested;
}

data 是要嵌套的数组(SQL 结果集),

groupkey 是“外部”实体主键的列名,

nestname 是要放入“内行”的字段的名称,

innerkey 是“内部”实体主键的列名。

在结果集中,“外部”实体的所有列都必须在 $innerkey 列之前,“内部”实体的所有列都必须跟在它之后。

要正确分组,结果集必须首先按来自“外部”实体的唯一表达式排序,例如order by badge_type_title, badge_type_id, ...order by 中的后续字段将定义“内部”组内的排序。

要嵌套连接 3 个或更多实体,您可以多次使用此函数(“从内到外”折叠)

【讨论】:

  • 添加了可能的 PHP 解决方案示例。在这里你可以在线测试它 - codepad.org/EqlkVYXV
  • 看起来很棒!下班回家我就试试看,谢谢!
猜你喜欢
  • 2012-09-10
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 2019-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多