使用PHP从三个MySQL表构建CSV表的有效方法

时间:2017-01-21 20:34:20

标签: php mysql sql performance csv

我想使用PHP从数据库中的数据构建CSV表。我是编程应用程序,持有儿童得分。我的第一张桌子只定义了孩子:

┏━━━━┳━━━━━━┓
┃ ID ┃ name ┃
┡━━━━╇━━━━━━┩
│  1 │ John │
│  2 │ Lucy │
│  3 │ Zara │
└────┴──────┘

第二个定义了儿童可以获得分数的事件

┏━━━━┳━━━━━━━━━━━━┓
┃ ID ┃    date    ┃
┡━━━━╇━━━━━━━━━━━━┩
│  1 │ 2016-12-31 │
│  2 │ 2017-01-07 │
│  3 │ 2017-01-14 │
│  4 │ 2017-01-21 │
└────┴────────────┘

并且第三个告诉我们在eventID

的事件中有多少积分带有childID的孩子
┏━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓
┃ ID ┃ eventID ┃ childID ┃ points ┃
┡━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩
│  1 │       1 │       1 │     21 │
│  2 │       1 │       2 │     43 │
│  3 │       1 │       3 │      4 │
│  4 │       2 │       1 │      8 │
│  5 │       2 │       2 │     15 │
│  6 │       2 │       3 │     13 │
│  7 │       3 │       1 │     34 │
│  8 │       3 │       2 │     40 │
│  9 │       3 │       3 │     20 │
│ 10 │       4 │       1 │      3 │
│ 11 │       4 │       2 │      7 │
│ 12 │       4 │       3 │      9 │
└────┴─────────┴─────────┴────────┘

让我们说我们有C子节目和E事件,因此表格点有C * E行。现在我想找到这样构建表的最有效方法:

     event;John;Lucy;Zara;⋯
2016-12-31;  21;  43;   4;
2017-01-07;   8;  15;  13;
2017-01-14;  34;  40;  20;
2017-01-21;   3;   7;   9;
     ⋮                   ⋱

它也可以是行< - > col swapped,但我发现的事件多于儿童。

但我对让C次E查询到数据库感到不舒服。我尝试用PHP生成冗长而丑陋的查询,但它基本上也使C次E子查询。我也知道如何只使用E查询来构建它,但是只有一个查询是不可能的?

1 个答案:

答案 0 :(得分:0)

考虑条件聚合,在MySQL中,您必须为每个子名称繁琐地做。如果太多不可行(即数百个),请考虑使用PHP动态构建SQL字符串。

SELECT e.date AS `event`, 
       SUM(CASE WHEN c.name = 'John' THEN j.points ELSE 0 END) As `John`,
       SUM(CASE WHEN c.name = 'Lucy' THEN j.points ELSE 0 END) As `Lucy`,
       SUM(CASE WHEN c.name = 'Zara' THEN j.points ELSE 0 END) As `Zara`   
FROM EventChildJoin j
INNER JOIN ChildTable c
   ON j.childID = c.ID
INNER JOIN EventTable e
   ON j.eventID = e.ID
GROUP BY e.date

如上所述,由于MySQL没有交叉表/数据透视方法,因此必须在应用程序层构建SQL,然后传入数据库层进行处理。以下是PHP的示例:

try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$database",$username,$password);    

    # FIRST FETCH
    $strSQL = "SELECT DISTINCT name FROM ChildTable";
    $STH = $dbh->query($strSQL);
    $STH->setFetchMode(PDO::FETCH_ASSOC);

    $strSQL = "SELECT e.date AS `event`, ";    
    while($row = $STH->fetch()) {  
        $strSQL = $strSQL . " SUM(CASE WHEN c.name = '". row['name'] ."' " .
                            "          THEN j.points ELSE 0 END) As `". row['name'] ."`,";
    }

    $strSQL = " FROM EventChildJoin j".
              " INNER JOIN ChildTable c ".
              "      ON j.childID = c.ID ".
              " INNER JOIN EventTable e ".
              "      ON j.eventID = e.ID ".
              " GROUP BY e.date;";
    $strSQL = str_replace(", FROM", " FROM", strSQL)    # REMOVE COMMA AFTER LAST COLUMN

   # NEXT FETCH
   $STH = null;
   $STH = $dbh->query($strSQL);
   $STH->setFetchMode(PDO::FETCH_ASSOC);
   ...    
}

catch(PDOException $e) {  
    echo $e->getMessage();
    exit;
}