1

我很难找到做某事的最佳方法。我在 mysql 中有三个表,这与我正在构建的健身房应用程序有关,一个用于肌肉锻炼,一个用于有氧运动,另一个用于存储用户每天每次锻炼的结果。每天的锻炼是基于 0 到 1 的有氧运动和 0 - 无论私人教练决定多少肌肉锻炼。在锻炼结束时,用户将每次锻炼的结果放入表格并提交。结果只是一个文本字段。我有一个数据库,它为每个单独的结果创建一行,其中包括

username,exercise type (muscle,cardio),exercise name, exercise result, date

所以一个例子是

John,muscle,bench press, 225lb max out, 2012-08-21
John,cardio,rowing,12 miles, 2012-08-21

然后,我想获取此信息并根据所选日期将其显示在标准表格中。所以每个日期有多个用户,每个用户可以有多个答案。标题将是

username,cardio, muscle 1, muscle 2 ect..(显示当天的数量)然后将结果向下并填写在表格中。

除了打几十个选择电话外,我还试图找出一种方法来做到这一点。我正在考虑尝试创建某种排序或数组并使用它。有任何想法吗?

4

3 回答 3

1

我会选择阵列。问题在于发送肌肉/心脏结果。

要以 HTML 格式格式化并获取标题,假设我们首先有有氧运动,然后是肌肉。

因此,您选择该日期的所有行,按用户名和有氧运动/肌肉排序。

然后:

$users = array();
$maxes = array('cardio' => 0, 'muscle' => 0);

foreach($row = ...)
{
    list($user, $com, $name, $result) = $row;
    if (!isset($users[$user]))
        $userData = array('cardio' => array(), 'muscle' => array());
    else
        $userData = $users[$user];
    $userData[$com][] = array($name, $result);
    if (count($userData[$com]) > $maxes[$com])
        $maxes[$com] = count($userData[$com]);
    $users[$user] = $userData;
}

现在你有类似的东西:

'John': {
     'cardio': [
        [ 'rowing', '12 miles' ],
        [ 'running', '2 miles' ],
     ],
     'muscle': [ ]
},
'Jack': {
     'cardio': [ ],
     'muscle': [ 'bench', '300lbs' ],
}

为了在 HTML 中格式化,我们保存了任何用户的最大有氧运动数量和最大肌肉数量。因此,1 + MaxC + MaxM 列的表将包含所有用户,按顺序排列:

Name  Cardio 1    Cardio 2   Muscle 1

John  Rowing      Running    -
      12 miles    2 miles
Jack  -           -          Bench
                             300lbs

并构建它:

// First the header
print "<tr>";
print "<th>Name</th>";
for ($i = 0; $i < $maxes['cardio']; $i++)
    print "<th>Cardio " . ($i+1) . "</th>";
for ($i = 0; $i < $maxes['muscle']; $i++)
    print "<th>Muscle ($i+1)</th>";
print "</tr>";

foreach($users as $user => $info)
{
    print "<tr><td>$user</td>";
    foreach(array('cardio','muscle') as $key)
    {
        $data = $info[$key];
        for ($i = 0; $i < $maxes[$key]; $i++)
        {
            print "<td>";
            if (isset($data[$i]))
            {
                list($name, $result) = $data[$i];
                print "$name<br />$result";
            }
            else print '-';
            print "</td>";  
        } 
    }
    print "</tr>";
 }
于 2012-08-21T18:15:45.117 回答
1

我会为 3NF 设置推荐 4 个表:

用户(用户名PK)
练习类型(PK 类型)
运动名称(名称PK)
练习条目(id PK,用户名 FK,日期,练习类型 FK,练习名称 FK,结果)

您将在其中生成练习条目exercise_entry并留下结果NULL。这样用户就知道有一个期望值。

在 PHP 端,您只需exercise_entry根据过滤器参数从表中获取数据。

编辑 1

如果练习类型和名称之间存在 1:1 的关系,则可以使用 3 表方法。

用户(用户名PK)
练习名称(名称PK,类型)
练习条目(id PK,用户名 FK,日期,练习名称 FK,结果)
于 2012-08-21T18:16:33.200 回答
1

首先,可能没有必要为三类运动中的每一种分别设置表格:也许一张exercises表格就足够了,用一列来指示每条记录是肌肉锻炼还是心血管锻炼?

关于您的问题:您要做的是对数据进行透视,这是 MySQL 开发人员故意不包含在本机中的功能(因为他们认为它更适合应用程序的表示层,而不是数据库层); 其他 RDBMS 可能对此类操作有更多的原生支持。但是,仍然可以通过对数据进行分组GROUP_CONCAT()并使用 MySQL 的函数聚合结果来实现您的目标:

SELECT   username,
         GROUP_CONCAT(IF(exercise='bench press',result,NULL)) AS `bench press`,
         GROUP_CONCAT(IF(exercise='rowing'     ,result,NULL)) AS `rowing`,
         -- etc.
FROM     results
WHERE    date = '2012-08-21'
GROUP BY username

如果练习列表是动态的,您可以生成包含此 SQL 语句的字符串,然后根据该字符串准备并执行语句:

SELECT CONCAT('
   SELECT   username,
', GROUP_CONCAT(
     'GROUP_CONCAT(IF(exercise=',QUOTE(name),',result,NULL))'
   ,    ' AS `',REPLACE(name,'`','``'),'`'
   )
,' FROM     results
   WHERE    date = ?
   GROUP BY username
') FROM exercises INTO @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt USING '2012-08-21';
DEALLOCATE PREPARE stmt;
于 2012-08-21T18:26:06.473 回答