Как отобразить сгруппированные данные в отдельных таблицах с помощью цикла PHP? - PullRequest
0 голосов
/ 27 октября 2018

Я новичок в phpmysqli.Вот что я имею и чего пытаюсь достичь: я буду обновлять это на основе рекомендаций; Пример базы данных

Я хочу отобразить данные на одной странице с отдельными таблицами для каждого учащегося в зависимости от их sid.Это то, что я пробовал до сих пор:

<?php
include_once 'dbcon.php';

$results = $MySQLiconn->query('SELECT * FROM activitybook');

$students = [];

foreach ( $results->fetch_array() as $activity ) {
    $students[$activity['sid']][] = $activity;
}

foreach($students as $sid=>$activities) {
    foreach($activities as $activity) {
         echo
                    "<table><tr>
                        <th>SID</th>
                        <th>Date</th>
                        <th>FName</th>
                        <th>LName</th>
                        <th>activity</th>
                        <th>time</th>
                        <th>score</th>
                        </tr>
                <tr>
                    <td>" . $sid . "</td>
                    <td>" . $activity['fname'] . "</td>
                    <td>" . $activity['lname'] . "</td>
                    <td>" . $activity['activity'] .  "</td>
                    <td>" . $activity['atime'] .  "</td>
                    <td>" . $activity['ascore'] .  "</td>
                </tr></table>";
    }
}
?>

Это то, что я получаю

То, что я пытаюсь достичь, - это отдельные таблицы для каждого sid. Это образец того, что я хочу заархивировать

Ответы [ 4 ]

0 голосов
/ 28 октября 2018

Требования: обработка потока заказанных студенческих записей. Поток состоит из групп студенческих записей. Каждая группа идентифицируется в столбце 'sid'.

  • Каждая StudentGroup упакована в таблицу HTML
  • Каждая StudentRecord является одной строкой таблицы

Что мне нравится делать, так это структурировать код в соответствии с данными. Данные структурированы следующим образом:

Итерация StudentRecordGroup

Каждая группа StudentRecordGroup состоит из последовательности:

  • Начало процесса группы
  • Итерация по записям, принадлежащим группе
  • Обработка конца группы

Обратите внимание, что в этом процессе нет условных выражений!

Теперь, как нам структурировать код для этого. Вы не можете использовать цикл foreach! Это только делает чтение в конце цикла.

У нас есть две петли:

  • Внешний цикл, который обрабатывает все группы записей.
  • Внутренний цикл, который обрабатывает Одна полная группа.

Техника для этого называется «читать вперед». И это только то, что он говорит. Вы читаете первую запись перед запуском внешнего цикла.

* Источник: 1039 *

Рабочий код на Pastebin.com

Выход:

SID Date    FName   LName   activity    time    score
2   John    Ppap    12  56  56
2   John    Ppap    23  23  23
SID Date    FName   LName   activity    time    score
3   Mito    Mmito   34  12  12
3   Mito    Mmito   45  45  45
SID Date    FName   LName   activity    time    score
4   Uba Uuba    56  78  100

Код:

 <?php // 53020396/how-to-display-grouped-data-in-separate-tables-with-a-php-loop

/* ---------------------------------------------------------------------------
 * The input stream consists of an Ordered Iteration of: 
 *    A collection of Individual Records for each Student (StudentRecordGoup)
 *    
 *  Each StudentRecordGoup consists of a Sequence of:
 *     Start of Group
 *     Iteration of Student records belonging to the group
 *     End of Group
 *
 *   Notice: There is no 'IF' statement anywhere in the control logic for a group! 
 *   
 *   Please note: There is exactly one place in the code to assign any appropriate action! 
 *                i.e. The structure of the code exactly matched the structure of the data. :)   
 * 
 *   This makes it easier to debug, maintain and amend?
 *   
 *   To do this we need 'state' information. Specifically that a record is part 
 *   of the current 'student record group' group or not. How do we do this?
 *    
 *   We always need a record to test! Including at the start! We never read a record
 *   and then decide what to do with it. We always know where we are in the data
 *   structure and either the current record belongs to the group or not. 
 *   
 *    We need to use a technique called 'Read Ahead'. Literally, There is always 
 *    a record to process. You don't have to test it to know where you are. 
 *    Once you process it then you immediately read the next record from the input. 
 *    i.e. You end up reading a new record NOT JUST AT THE WND OF THE LOOP! 
 *    You cannot use 'foreach' loops. 
 *   
 *   We have to include Initialisation to setup code and any termination code.
 *   
 *   I will put all the 'action place holders' in functions. That way it avoids
 *   obscuring the high-level logic.
 */

// Get the ordered student detail records
$pdo = getPdoConnection();
$pdoResultSet = prepareAndExecuteQuery($pdo);


// Process all the students Record Groups  - 'read ahead' of the row  
$curStudentRecord = $pdoResultSet->fetch();  // is assoc array 

while ($curStudentRecord !== false)  { // process the student record groups

   // process one complete student group...
   $curStudentRecordGroupId = $curStudentRecord['sid'];
   startStudendRecordGroup($curStudentRecordGroupId);
   while (   $curStudentRecord !== false  // check record belongs to the current group 
          && $curStudentRecord['sid'] === $curStudentRecordGroupId) {

        processStudentRecord($curStudentRecord);
        $curStudentRecord = $pdoResultSet->fetch();  // read the next record 
    }

   endStudendRecordGroup($curStudentRecordGroupId); // ignore the current record
                                                    // that is the next group!
}
// all groups have been processed
exit;

/* --------------------------------------------------------------------------
 * Student record group processing
 */
function startStudendRecordGroup($curStudentRecordGroupId)
{
    echo "<!-- new group: sid = $curStudentRecordGroupId -->"; 
    echo "<table><tr><th>SID</th><th>Date</th><th>FName</th><th>LName</th>
                     <th>activity</th><th>time</th><th>score</th></tr>";
}

function processStudentRecord($curStudentRecord)
{
    echo "<!-- group record: sid = {$curStudentRecord['sid']} -->";
    echo "<tr>
                    <td>" . $curStudentRecord['sid'] . "</td>
                    <td>" . $curStudentRecord['fname'] . "</td>
                    <td>" . $curStudentRecord['lname'] . "</td>
                    <td>" . $curStudentRecord['col3'] .  "</td>
                    <td>" . $curStudentRecord['col4'] .  "</td>
                    <td>" . $curStudentRecord['col5'] .  "</td>
                </tr>"; 
}

function endStudendRecordGroup($curStudentRecordGroupId)
{
    echo "<!-- end group: sid = $curStudentRecordGroupId -->";
    echo "</table>"; 
}

/* --------------------------------------------------------------------------
 * Database access
 */

// Execute query and return 'resultset'
function prepareAndExecuteQuery(\PDO $pdo)
{
   $sql = 'SELECT id, sid, fname, lname, col3, col4, col5 
           FROM activity
           ORDER BY sid, id';

   $stmt = $pdo->prepare($sql);
   $allOk = $stmt->execute();
   return $stmt;          
}

// DB Connection 
function getPdoConnection()
{
    $opt  = array(
                \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, 
                \PDO::ATTR_EMULATE_PREPARES   => false,
            );

    $pdo = new \PDO('mysql:host=localhost;dbname=notmydb;', 'notme', 'notme', $opt);
    return $pdo;             
}
0 голосов
/ 27 октября 2018

Сгруппируйте свои результаты по SID, затем выполните цикл:

$results = $conn->query('SELECT * FROM activitybook');

$students = []

foreach ( $results->fetch_array() as $activity ) {
    $students[$activity['sid']][] = $activity;
}

foreach($students as $sid=>$activities) {
    foreach($activities as $activity) {
         echo
                    "<table><tr>
                        <th>SID</th>
                        <th>Date</th>
                        <th>FName</th>
                        <th>LName</th>
                        <th>activity</th>
                        <th>time</th>
                        <th>score</th>
                        </tr>
                <tr>
                    <td>" . $sid . "</td>
                    <td>" . $activity['fname'] . "</td>
                    <td>" . $activity['lname'] . "</td>
                    <td>" . $activity['activity'] .  "</td>
                    <td>" . $activity['atime'] .  "</td>
                    <td>" . $activity['ascore'] .  "</td>
                </tr></table>";
    }
}

Несколько советов для вас:

  • Используйте переменные со значениями имен.Что внутри твоего $row?Деятельность правильно?Поэтому назовите его $activity.И избегайте сокращений, таких как $res.
  • То же самое верно для столбцов вашей базы данных.aid не очень хорошая практика.Используйте только идентификатор для первичного ключа.Также sid должно стать student_id, чтобы люди, читающие ваш код, понимали, что это внешний ключ для таблицы студентов.
0 голосов
/ 27 октября 2018

Вы можете создать отдельный массив идентификаторов учеников и каждый раз в цикле проверять, существует ли этот идентификатор в массиве, чем не создавать новую таблицу, иначе создавать новую таблицу. Используйте как это:

<?php
$res = $conn->query("SELECT * FROM activitybook");
$sId = [];
echo "<table>";
while($row=$res->fetch_array())
{
    if (count($sId) == 0) {
        $sId[] = $row['sid'];
    }
    if (!in_array($row['sid'], $sId)) {
        $sId[] = $row['sid'];
        echo "</table><table>";
    }
    echo
        "<tr>
                <th>SID</th>
                <th>Date</th>
                <th>FName</th>
                <th>LName</th>
                <th>activity</th>
                <th>time</th>
                <th>score</th>
                </tr>
        <tr>
            <td>" . $row['sid'] . "</td>
            <td>" . $row['fname'] . "</td>
            <td>" . $row['lname'] . "</td>
            <td>" . $row['activity'] .  "</td>
            <td>" . $row['atime'] .  "</td>
            <td>" . $row['ascore'] .  "</td>
        </tr>";
}
?>
0 голосов
/ 27 октября 2018

Вам нужно будет «сгруппировать» данные набора результатов на основе значения sid. Во время итерации проверьте, меняете ли вы группы или нет.

Я также добавил некоторые уточнения.

  • Назовите столбцы в предложении SELECT, чтобы вы получали только то, что вам нужно.
  • Получить ассоциативный массив, а не комбинацию индексированных и ассоциативных элементов.
  • Назначьте временную переменную, чтобы определить, продолжаете ли вы группу sid или начинаете новую (или если это первая итерация, не пишите </table>.
  • implode() помогает удалить большую часть кода.

Код:

$res = $conn->query("SELECT sid, fname, lname, activity, atime, ascore FROM activitybook ORDER BY sid");
$tmp = null;
$colheads = ['SID', 'FName', 'LName', 'activity', 'time', 'score'];
while ($row = $res->fetch_assoc()) {   // don't produce more elements per row than needed
    if ($tmp != $row['sid']) {  // determine if a new group / sid value
        if ($tmp !== null) {
            echo '</table><br>';  // close the previous table
        }
        echo '<table border=1><tr><th>' , implode('</th><th>', $colheads) , '</th></tr>';  // start a new table & add headings
    }
    echo '<tr><td>' , implode('</td><td>', $row) , '</td></tr>';  // display the row data
    $tmp = $row['sid'];   // DUH, I FORGOT TO UPDATE $tmp!
}
if ($tmp !== null) {
    echo '</table>';  // close the final table -- so long as there was at least one row in the result set
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...