0

MYSQL クエリからネストされた配列を返そうとしています。投稿、ユーザー、キーワード、およびカテゴリのテーブルがあり、クエリを最適化して、あまり多くの選択がないようにしたいと考えています。現在SELECT、1 つの投稿に対して 4 つのクエリがあり、それぞれが をループし、foreachPHP でネストされた配列を作成しています。それらをより少ないクエリに統合し、実行を高速化する方法はありますか?

1 行は次のようになります。キーワード、カテゴリ、および著者番号はすべて、それぞれのテーブルの ID です。

投稿表:

| id | title |    content     | keywords | category | author |
|----|-------|----------------|----------|----------|--------|
|  1 | Test  | Lorem ipsum... | 1, 2     |        1 |      1 |
|----|-------|----------------|----------|----------|--------|

キーワード表:

| id |   name   |   url    |  description   |
|----|----------|----------|----------------|
|  1 | keyword1 | keyword1 | Lorem ipsum... |
|  2 | keyword2 | keyword2 | Lorem ipsum... |
|----|----------|----------|----------------|

ユーザー テーブル:

| id |   name   |    email     |
|----|----------|--------------|
|  1 | John Doe | john@doe.com |
|----|----------|--------------|

カテゴリ表:

| id |   name    |    url    |
|----|-----------|-----------|
|  1 | Category1 | category1 |
|----|-----------|-----------|

達成したい出力は次のとおりです。

Array
(
    [0] => Array
    (
        [id] = 1
        [title] = Test
        [content] = Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias, sapiente assumenda ratione dicta cumque accusantium id labore cupiditate maiores obcaecati repudiandae at eum fuga doloremque commodi. Quidem, nulla cupiditate aperiam!
        [keywords] => Array
            (
                [0] => Array
                (
                    [id] => 1
                    [name] => keyword1
                    [url] => keyword1
                    [description] => Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores, dolorem, consectetur voluptatem amet hic placeat alias rerum unde quis quia aperiam officia aliquam incidunt sit fugit quo iusto porro repellat!
                )
                [1] => Array
                (
                    [id] => 2
                    [name] => keyword2
                    [url] => keyword2
                    [description] => Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam, culpa, repudiandae voluptatibus odit nam id sed maxime ullam quia accusamus minima nisi! Dolor, doloremque similique voluptatibus at eos vitae id?
                )
        )
        [category] => Array
        (
            [id] => 1
            [name] => Category1
            [url] => category1
        )
        [author] => Array
        (
            [id] => 1
            [name] => John Doe
            [email] => john@doe.com
        )
    )
)
4

2 に答える 2

1

まず、データを正規化する必要があります。次のような post_keywords の新しいテーブルを作成します。

| post_id | keyword_id |
|---------|------------|
|       1 |          1 |
|       1 |          2 |
|---------|------------|

次に、必要なデータを取得するのは単純な JOIN です。

post_keywords テーブルを作成したら、次のようなことができます。

    $db = new PDO('mysql:host=localhost;dbname=<SOMEDB>', '<USERNAME>', 'PASSWORD');

    $sql = "
       SELECT p.id      as p_id
          ,p.title   as p_title
          ,p.content as p_content
          ,c.id      as c_id
          ,c.name    as c_name
          ,c.url     as c_url
          ,u.id      as u_id
          ,u.name    as u_name
          ,u.email   as u_email
          ,GROUP_CONCAT( CONCAT( k.id, '|', k.name, '|', k.url, '|', k.description )
                         SEPARATOR '||' ) as keywords

      FROM posts p

      LEFT OUTER
      JOIN post_keywords pk
        ON pk.post_id = p.id

      LEFT OUTER
      JOIN keywords k
        ON k.id = pk.keyword_id

      LEFT OUTER
      JOIN category c
        ON c.id = p.category

      LEFT OUTER
      JOIN user u
        ON u.id = p.author

     GROUP BY p.id";

    $final = array();
    $results = $db->query( $sql );
    while ( $row = $results->fetch(PDO::FETCH_ASSOC) ) {
            $k = array();
        foreach ( ecplode( '||', $row[ 'keywords' ] as $kw ) {
            $kw = explode( '|', $kw );
            $k[] = array( 'id' => $kw[0], 'name' => $kw[1], 'url' => $kw[2], 'description' => $kw[3] );
        }
        $final[] = array( 'id'       => $row[ 'p_id' ]
                , 'title'    => $row[ 'p_title' ]
                , 'content'  => $row[ 'p_content' ]
                , 'keywords' => $k
                , 'category' => array( 'id' => $row[ 'u_id' ], 'name' => $row[ 'u_name' ], 'url' => $row[ 'c_url' ] )
                , 'author'   => array( 'id' => $row[ 'u_id' ], 'name' => $row[ 'u_name' ], 'email' => $row[ 'u_email' ] )
                );
    }

これはテストされていないため、100% ではない可能性があることに注意してください。SQL は、キーワードなしの投稿、および/または null カテゴリまたは作成者を含む投稿が可能であると想定しています。そうでない場合は、JOIN から「LEFT OUTER」を削除できます。

配列は、$final必要に応じてフォーマットする必要があります。SQL は、 http: //sqlfiddle.com/#!2/fd630/1 の SQL Fiddle で確認できます。

アップデート

上記の SQL の代わりに次の SQL を使用して、現在のテーブルで同じことを行うことができます (post_keywords は必要ありません)。すべてのキーワード ID が、スペースが埋め込まれていないコンマで区切られていることを前提としています。

SELECT p.id      as p_id
      ,p.title   as p_title
      ,p.content as p_content
      ,c.id      as c_id
      ,c.name    as c_name
      ,c.url     as c_url
      ,u.id      as u_id
      ,u.name    as u_name
      ,u.email   as u_email
      ,GROUP_CONCAT( CONCAT( k.id, '|', k.name, '|', k.url, '|', k.description )
                     SEPARATOR '||' ) as keywords

  FROM posts p

  LEFT OUTER
  JOIN keywords k
    ON k.id REGEXP REPLACE(p.keywords,',','|')

  LEFT OUTER
  JOIN category c
    ON c.id = p.category

  LEFT OUTER
  JOIN user u
    ON u.id = p.author

 GROUP BY p.id

このための SQLFiddle はhttp://sqlfiddle.com/#!2/2e1ec7/2にあります。

于 2013-09-14T20:14:12.120 に答える