Topic 7: Calculate, logical operation, table print
๐ 13 min read ยท ๐ฏ intermediate ยท ๐งญ Prerequisites: javascript-validation, joint-query-nested-query-filtering-data
Why this matters
Up until now, you've probably stared at raw data โ a list of names, numbers, or entries โ and thought, "How do I make sense of this?" Every real project eventually needs you to do three things at once: crunch some numbers, apply a rule or condition, and display the result in a way anyone can read at a glance. In this lesson, we'll pull data from a database, run PHP's arithmetic and logical operations on it, and render everything into a clean HTML table. By the end, you'll know how to go from messy rows to a readable report โ a skill you'll use in almost every project you build.
What You'll Learn
- How to execute aggregate SQL queries (
COUNT,AVG,LENGTH,GROUP BY) from PHP usingmysqli - How to store and iterate over grouped query results in a PHP associative array
- How to apply logical operators in PHP to make threshold-based decisions
- How to combine PHP and HTML to render a styled, data-driven table
The Analogy
Think of a city census office. The raw data lives in filing cabinets (the database). A clerk (PHP) pulls the drawers, counts the folders (COUNT(*)), sorts them by district (GROUP BY Track), and measures the average length of the ID numbers (AVG(LENGTH(...))). Once the clerk has those figures, a simple rulebook (logical operators) decides whether the ID format meets the legal standard. Finally, a typesetter (the HTML table) formats every result into a clean printed report the mayor can hand out at the summit. The filing cabinet doesn't care how the report looks; the typesetter doesn't know how to count โ each layer does exactly one job.
Chapter 1: PHP Calculations
the trainer opened the session by connecting PHP to the InnovatorsSummit database and firing three aggregate queries: total participant count, participants grouped by track, and the average length of contact numbers.
Key SQL functions used
| Function | What it does |
|---|---|
COUNT(*) | Counts every row that matches the query |
GROUP BY | Collapses rows into groups before counting |
AVG() | Returns the arithmetic mean of a numeric column |
LENGTH() | Returns the character length of a string value |
Full calculation script
<?php
// Database configuration
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "InnovatorsSummit";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Calculate total number of participants
$totalParticipantsQuery = "SELECT COUNT(*) AS total FROM Participants";
$totalResult = $conn->query($totalParticipantsQuery);
$totalParticipants = $totalResult->fetch_assoc()['total'];
// Calculate number of participants in each track
$tracksQuery = "SELECT Track, COUNT(*) AS count FROM Participants GROUP BY Track";
$tracksResult = $conn->query($tracksQuery);
$tracks = [];
while ($row = $tracksResult->fetch_assoc()) {
$tracks[$row['Track']] = $row['count'];
}
// Calculate average contact number length
$contactLengthQuery = "SELECT AVG(LENGTH(ContactNumber)) AS averageLength FROM Participants";
$contactLengthResult = $conn->query($contactLengthQuery);
$averageContactLength = $contactLengthResult->fetch_assoc()['averageLength'];
$conn->close();
?>
Walk-through of the data flow
new mysqli(...)opens the connection;connect_errorguards against misconfiguration.- The first query returns one row with one column (
total).fetch_assoc()['total']plucks that value directly. - The second query returns one row per track. The
whileloop builds an associative array$trackskeyed by track name, valued by participant count โ perfect for iterating later. - The third query returns one row (
averageLength) viaAVG(LENGTH(ContactNumber))โ nesting a string function inside an aggregate function in a single SQL expression. $conn->close()releases the connection before the page renders.
Chapter 2: Logical Operations
With $averageContactLength in hand, the trainer showed the class how PHP's comparison and boolean operators turn a raw number into a decision.
Concept: comparison operators in PHP
| Operator | Meaning |
|---|---|
> | Greater than |
< | Less than |
>= | Greater than or equal to |
== | Loose equality |
=== | Strict equality (type + value) |
!= | Not equal |
Threshold check script
<?php
// Define a threshold for the average contact number length
$threshold = 10;
// Check if the average contact number length exceeds the threshold
$isExceedingThreshold = $averageContactLength > $threshold;
if ($isExceedingThreshold) {
echo "The average contact number length exceeds the threshold.";
} else {
echo "The average contact number length is within the acceptable range.";
}
?>
$isExceedingThreshold stores the boolean result of $averageContactLength > $threshold. Assigning the result of a comparison to a named variable โ rather than embedding it directly in the if โ makes the intent readable at a glance and lets you reuse the value multiple times (as the table section does below).
Chapter 3: Printing Tables
The class's final task was rendering all three data points โ total participants, the per-track breakdown, and the contact-length verdict โ into an HTML page anyone could open in a browser. PHP is embedded directly inside the HTML using <?php ... ?> tags.
Complete PHP + HTML table output
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Innovators' Summit Data</title>
<style>
table {
width: 50%;
border-collapse: collapse;
margin: 25px 0;
font-size: 18px;
text-align: left;
}
th, td {
padding: 12px;
border: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h1>Innovators' Summit Data</h1>
<h2>Total Participants</h2>
<p><?php echo $totalParticipants; ?></p>
<h2>Participants by Track</h2>
<table>
<thead>
<tr>
<th>Track</th>
<th>Number of Participants</th>
</tr>
</thead>
<tbody>
<?php foreach ($tracks as $track => $count) : ?>
<tr>
<td><?php echo $track; ?></td>
<td><?php echo $count; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h2>Average Contact Number Length</h2>
<p><?php echo $averageContactLength; ?></p>
<h2>Contact Length Check</h2>
<p>
<?php echo $isExceedingThreshold
? "The average contact number length exceeds the threshold."
: "The average contact number length is within the acceptable range.";
?>
</p>
</body>
</html>
Key patterns in this template
border-collapse: collapseโ merges adjacent cell borders into a single line instead of doubling them.<?php foreach ($tracks as $track => $count) : ?> ... <?php endforeach; ?>โ the alternativeforeachsyntax (:/endforeach) keeps HTML readable inside loops; it is equivalent toforeach (...) { }but avoids nested braces cluttering the markup.- Ternary operator in output โ
$isExceedingThreshold ? "..." : "..."is PHP's inlineif/else, used here directly insideechoto keep the display logic tight.
flowchart LR
DB[(InnovatorsSummit DB)] -->|COUNT * | A[totalParticipants]
DB -->|GROUP BY Track| B[$tracks array]
DB -->|AVG LENGTH | C[averageContactLength]
C --> D{> threshold?}
D -- yes --> E[Exceeds threshold message]
D -- no --> F[Within range message]
A --> G[HTML Page]
B --> G
C --> G
E --> G
F --> G
๐งช Try It Yourself
Task: Create a PHP page that connects to a local school database containing a students table with columns id, name, grade (A/B/C/D/F), and phone. The page should:
- Display the total number of students.
- Display a table of grade counts (how many students per grade letter).
- Check whether the average phone number length is at least 10 characters, and print a message accordingly.
Success criterion: When you open the page in a browser you should see three sections โ a total count, a two-column grade breakdown table, and one of the two threshold messages โ all populated from live database rows.
Starter snippet (connection + first query):
<?php
$conn = new mysqli("localhost", "root", "", "school");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$total = $conn->query("SELECT COUNT(*) AS total FROM students")
->fetch_assoc()['total'];
// Add grade breakdown and AVG(LENGTH(phone)) queries here
?>
๐ Checkpoint Quiz
Q1. What does the SQL expression AVG(LENGTH(ContactNumber)) calculate, and why are two functions nested together?
Q2. Given the following snippet, what is printed when $averageContactLength is 9.5 and $threshold is 10?
<?php
$threshold = 10;
$isExceedingThreshold = $averageContactLength > $threshold;
echo $isExceedingThreshold
? "Exceeds threshold."
: "Within range.";
?>
A) Exceeds threshold. B) Within range. C) Nothing โ the ternary syntax is invalid in PHP. D) A PHP warning about an undefined variable.
Q3. What is the purpose of border-collapse: collapse in the table CSS, and what would the table look like without it?
Q4. How would you modify the $tracksQuery to only include tracks with more than 5 participants?
A) Add WHERE count > 5 before GROUP BY
B) Add HAVING COUNT(*) > 5 after GROUP BY
C) Add LIMIT 5 after GROUP BY
D) Use FILTER BY count > 5 after GROUP BY
A1. LENGTH(ContactNumber) computes the character length of each contact number string; AVG(...) then averages those lengths across all rows. The two functions are nested because SQL evaluates the inner function per row first, then the outer aggregate collapses all row-level results into one summary value.
A2. B โ 9.5 > 10 evaluates to false, so $isExceedingThreshold is false and the ternary prints "Within range."
A3. border-collapse: collapse merges adjacent cell borders so each edge between cells appears as a single line. Without it, the default separate model renders a gap between every pair of cells, making the table look double-bordered and visually heavier.
A4. B โ HAVING filters on aggregated values (counts, averages) after GROUP BY groups the rows. WHERE filters before aggregation and cannot reference COUNT(*) results; LIMIT restricts the number of output rows; FILTER BY is not valid SQL.
๐ช Recap
- PHP's
mysqlilets you fire aggregate SQL queries (COUNT,AVG,LENGTH,GROUP BY) and capture their results withfetch_assoc(). - Grouped query results are best collected into a PHP associative array with a
whileloop, then iterated in HTML withforeach. - Comparison operators (
>,<,===) return booleans you can store in named variables for readable, reusable logical checks. - PHP's alternative
foreach (...) : ... endforeach;syntax keeps HTML templates clean when looping inside markup. - Combining PHP calculations, logical operators, and HTML tables in a single
.phpfile is the standard pattern for rendering dynamic, database-driven reports.
๐ Further Reading
- PHP mysqli documentation โ the source of truth on
mysqliconnections, queries, and result fetching - PHP Operators โ full reference for comparison, logical, and ternary operators in PHP
- MySQL Aggregate Functions โ official docs for
COUNT,AVG,SUM,GROUP BY, andHAVING - MDN: CSS border-collapse โ explains separate vs. collapse table border models with visual examples
- โฌ ๏ธ Previous: Joint Query, Nested Query, Filtering DATA
- โก๏ธ Next: JavaScript Cookies