1

私はテーブルを持っています:

CREATE TABLE `Issues` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

私は別のテーブルを持っています:

CREATE TABLE `Attachments` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `issue_id` int(11) DEFAULT NULL,
  `attachment` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

データを次のようにするにはどうすればよいですか?

issue_id    title    attachment1    attachment2    attachment3
--------------------------------------------------------------
1           T1       a1.png         a2.png
2           T2
3           T3       b4.gif         xyz.doc        ttt.file

私が理解できない問題は、添付ファイルの動的セットを問題ごとにグループ化された動的列に入れる方法です。1つの問題の添付ファイルの最大数は12であると判断しましたが、チケットあたりの合計は0〜12の範囲です。私は困惑しています...

このMySQLピボット行を動的な列数で試しまし たが、レコードごとの合計一致数に基づいて動的な列を作成しているため、私の場合は意味がありません...

どんな助けでも大歓迎です。これが意味をなさない場合はお知らせください。

ニノ

4

2 に答える 2

2

SELECTステートメントによって返される列のセットは静的に定義されます。SELECTステートメントは、「可変」数の列を返すことはできません。

返される列を定義できれば、表示する結果セットを作成できます。これは、この場合、attachment行に返される値(列)の最大数を定義することを意味します。

その結果セットを取得するための1つのアプローチは、SELECTリストで相関サブクエリを使用して、値の1番目、2番目、3番目などのオカレンスを返すことattachmentです。

SELECT i.id
     , i.title
     , ( SELECT a1.attachment
           FROM `Attachments` a1
          WHERE a1.issue_id = i.id
          ORDER BY a1.id
          LIMIT 0,1
        ) AS attachment1
     , ( SELECT a2.attachment
           FROM `Attachments` a2
          WHERE a2.issue_id = i.id
          ORDER BY a2.id
          LIMIT 1,1
        ) AS attachment2
     , ( SELECT a3.attachment
           FROM `Attachments` a3
          WHERE a3.issue_id = i.id
          ORDER BY a3.id
          LIMIT 2,1
        ) AS attachment3
  FROM `Issues` i
 ORDER BY i.id

添付ファイルの最大数を返すには、それを拡張する必要があります...

     , ( SELECT a4.attachment
           FROM `Attachments` a4
          WHERE a4.issue_id = i.id
          ORDER BY a4.id
          LIMIT 3,1
        ) AS attachment4

ORDER BYの目的は、クエリの結果セットを決定論的にすることです(ORDER BYがない場合、MySQLは任意の順序で行を返すことができます)。

LIMIT句の目的は、1行のみが返されるように指定することです。LIMIT 0,1最初の行(0)から始めて、1行が返されることを指定します。 LIMIT 1,12行目のみを返します。


これが唯一のアプローチではなく、最も効率的ではない可能性があります。これは、外部クエリ(この場合はテーブルから)から返される少数の行に対して適切に機能しIssuesます。このステートメントに対して生成される「ネストされたループ」プランは、大規模なセットに対してリソースを大量に消費する(つまり低速になる)可能性があります。

最高のパフォーマンスを得るには、インデックスが必要になる可能性があります...

ON `Attachments` (issue_id, id) 

または少なくとも

ON `Attachments` (issue_id)

本当に「動的な」数値を返す必要がある場合は、attachment値を個別の行として返し、クライアント側でSQLステートメントから返された結果セットを処理する方が適切です。

于 2013-02-09T00:27:23.327 に答える
2

最大数が12であることがわかっている場合、これを実現する1つの方法があります。これはとを使用MAXしてCASE、各添付ファイルの行番号を取得します。

SELECT 
    I.Id issue_id, 
    I.title, 
    MAX(CASE WHEN d.row_number = 1 THEN D.attachment END) attachment1,
    MAX(CASE WHEN d.row_number = 2 THEN D.attachment END) attachment2,
    MAX(CASE WHEN d.row_number = 3 THEN D.attachment END) attachment3,
    MAX(CASE WHEN d.row_number = 4 THEN D.attachment END) attachment4,
    MAX(CASE WHEN d.row_number = 5 THEN D.attachment END) attachment5,
    MAX(CASE WHEN d.row_number = 6 THEN D.attachment END) attachment6,
    MAX(CASE WHEN d.row_number = 7 THEN D.attachment END) attachment7,
    MAX(CASE WHEN d.row_number = 8 THEN D.attachment END) attachment8,
    MAX(CASE WHEN d.row_number = 9 THEN D.attachment END) attachment9,
    MAX(CASE WHEN d.row_number = 10 THEN D.attachment END) attachment10,
    MAX(CASE WHEN d.row_number = 11 THEN D.attachment END) attachment11,
    MAX(CASE WHEN d.row_number = 12 THEN D.attachment END) attachment12
FROM Issues I
  LEFT JOIN (
  SELECT 
      a.issue_id, 
      @running:=if(@previous=a.issue_id,@running,0) + 1 as row_number,
      @previous:=a.issue_id,
      a.attachment
  FROM Attachments a
      JOIN    (SELECT @previous := 0) r
    ORDER BY a.issue_id, a.attachment
  ) D ON I.ID = D.issue_id
GROUP BY I.Id, I.Title

そして、これがSQLFiddleです。

グループごとに行番号をリセットするように編集する必要がありました。今働いているはずです。また、@ spencer7593のすばらしいコメントに従って、クエリを少し更新しました。

- 編集 -

動的な結果が必要であるというOPのコメントに応えて、これは機能するはずです。

SET @sql = NULL;

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(IF(d.row_number = ', d.row_number, ',D.attachment,NULL)) AS attachment', d.row_number)
  ) INTO @sql
FROM Issues I
  LEFT JOIN (
  SELECT 
      a.issue_id, 
      @running:=if(@previous=a.issue_id,@running,0) + 1 as row_number,
      @previous:=a.issue_id,
      a.attachment
  FROM Attachments a
      JOIN    (SELECT @previous := 0) r
    ORDER BY a.issue_id, a.attachment
  ) D ON I.ID = D.issue_id
;

SET @sql = CONCAT('SELECT I.Id issue_id, 
                          I.title, ', @sql, ' 
                  FROM Issues I
                  LEFT JOIN (
                  SELECT 
                      a.issue_id, 
                      @running:=if(@previous=a.issue_id,@running,0) + 1 as row_number,
                      @previous:=a.issue_id,
                      a.attachment
                  FROM Attachments a
                      JOIN    (SELECT @previous := 0) r
                    ORDER BY a.issue_id, a.attachment
                  ) D ON I.ID = D.issue_id
                GROUP BY I.Id, I.Title');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

そして、これがSQLFiddleです。

于 2013-02-09T00:33:13.870 に答える