1

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クエリでそれを行うことができますが、理想的には、可能であれば1つのクエリを使用したいですか?

4

1 に答える 1

2

SQL クエリでこれを達成することはできません。これは、(リレーショナル モデルの性質により) SQL クエリは常にネストなしで「フラット」な結果セットを返すためです (まれな例外は、ベンダーの SQL 拡張であり、XML 出力の生成などを対象としていますが、MySQL にはそのような拡張子はありません)。

SQL 結果セットからネストされた配列を取得する場合は、PHP コードで後処理する必要があります。このコードは、「内部」テーブルのキーが変更されるたびに新しいグループを開始する、配列に対するグループ化ループ (SQL で事前にソート) のように編成できます。これは PHP でかなり普遍的な方法で実行できるため、そのような関数を 1 つ記述して、多くの SQL クエリを後処理することができます (適切なパラメーターを指定します)。

追加ここにそのような関数があります:

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 つ以上のエンティティの結合をネストするには、この関数を数回使用できます (「内側から外側へ」折りたたむ)。

于 2013-10-26T08:30:31.783 に答える