Question

I'm new SQL and PHP and I'm trying implement a table showing content from 3 tables (all linked with another table containing foreign keys)

My main table consists of job_id, staff_id*, series_id* and channel_id*. All with * link to another table where they are primary key. I want show all the other tables information on in one big table using PHP.

So far I am able to display my main table without any of the others tables information with the following, I am stuck on where to go from here, as this is all new to me.

    <?php
$dbconnect=mysqli_connect('localhost', 'user', 'pass', 'database');
 // Check connection
 if (mysqli_connect_errno())
   {
   echo "Failed to connect to MySQL: " . mysqli_connect_error();
   }

 $result = mysqli_query($dbconnect,"SELECT * FROM JOB_LIST");
 echo "<table border='1'>
 <tr>
 <th>Job ID</th>
 <th>Staff ID</th>
 <th>Channel ID</th>
 <th>Series ID</th>
 </tr>";
 while($row = mysqli_fetch_array($result))
   {
   echo "<tr>";
   echo "<td>" . $row['JOB_STAFF'] . "</td>";
   echo "<td>" . $row['JOB_CHANNEL'] . "</td>";
   echo "<td>" . $row['JOB_SERIES'] . "</td>";
   echo "</tr>";
   }
 echo "</table>";
 mysqli_close($dbconnect);
 ?> 

I need to SELECT from JOB_LIST (Main linking table), STAFF_LIST, SERIES_LIST & CHANNEL_LIST. End result table rows should be:

echo "<td>" . $row['JOB_STAFF'] . "</td>"; //REFERENCES STAFF_ID
echo "<td>" . $row['STAFF_FIRSTNAME'] . "</td>";
echo "<td>" . $row['STAFF_SURNAME'] . "</td>";
echo "<td>" . $row['STAFF_EMAIL'] . "</td>"; 
echo "<td>" . $row['JOB_CHANNEL'] . "</td>"; //REFERENCES CHANNEL_ID
echo "<td>" . $row['CHANNEL_NAME'] . "</td>";
echo "<td>" . $row['CHANNEL_NETWORK'] . "</td>";    
echo "<td>" . $row['JOB_SERIES'] . "</td>"; //REFERENCES SERIES_ID
echo "<td>" . $row['SERIES_NAME'] . "</td>";
echo "<td>" . $row['SERIES_COUNT'] . "</td>";

But I have no idea what needs changing to implement it. If I haven't explained something, I apologise will attempt to explain something better.

Was it helpful?

Solution

As already said LEFT OUTER JOIN is what you need.

A few words about joins

A simple CROSS JOIN between two tables without any conditions is nothing else than a cross product. Columns will be added together and rows will me multiplied. So if you have one table with 3 columns and 20 rows and another with 5 columns and 1000 rows the joined table will have 3 + 5 = 8 columns and 20 * 1000 = 20,000 rows.

Normally you don't need the whole cross product. That's why you can make use of conditions. An INNER JOIN is like a CROSS JOIN but with an additional ON keyword defining the join condition to reduce the number of resulting rows to your needs. That means every row that doesn't comply with the condition is sorted out. Technically it's identical to a WHERE clause but you shouldn't mix that up, because semantically it's a very different beast. Usually, the join condition matches primary keys.

It's possible to perform multiple joins where the result of the first table joined with the second will be joined with the third an so on.

SELECT * FROM table_1 AS t1
    INNER JOIN table_2 AS t2
    ON t1.foreign_key_1 = t2.primary_key
    INNER JOIN table_3 AS t3
    ON t1.foreign_key_2 = t3.primary_key;

As you can see I also used the AS keyword to give alias names to the tables. This is important, because different tables might have identical field names. These so called qualified names avoid any possible name clashes.

But the INNER JOIN is still not what you're looking for. You have the following situation:

You want one row in your output table for every distinct Job ID. It should always be present, no matter if it references the entire set of foreign keys (staff_id, channel_id, series_id) or only a few, e.g. staff_id and channel_id or no entries at all.

An INNER JOIN would reject all those partial rows due to the fact that the ON condition must be true for both sides (tables) of the join. Fortunately, a LEFT OUTER JOIN assures that the table to the left will keep all its rows and looks for those that match the ON condition in the table to the right. Columns in rows that couldn't be matched will be filled up with NULL values. A RIGHT OUTER JOIN just works the other way round, as you might have guessed.

Well, that's the query you need.

SELECT li.id AS job_id, st.id AS staff_id, st.firstname AS staff_firstname, st.surname AS staff_surname,
    st.email AS staff_email, ch.id AS channel_id, ch.name AS channel_name,
    ch.network AS channel_network, se.id AS series_id, se.name AS series_name,
    se.count AS series_count
    FROM job_list AS li
    LEFT OUTER JOIN job_staff AS st
    ON li.staff_id = st.id
    LEFT OUTER JOIN job_channel AS ch
    ON li.channel_id = ch.id
    LEFT OUTER JOIN job_series AS se
    ON li.series_id = se.id;

And here's the updated PHP part. You probably have to adjust a few column and table names to your needs, because I can't foretell your database name and your table schemata. But based on this SQL Fiddle I made, it should work exactly how you want it. Scroll to the bottom and you see the table resulting from your query.

$dbconnect=mysqli_connect('localhost', 'user', 'pass', 'test');

// Check connection
if (mysqli_connect_errno())
{
    echo "Failed to connect to MySQL: " . mysqli_connect_error();
}

$query = "SELECT li.id AS job_id, st.id AS staff_id, st.firstname AS staff_firstname, st.surname AS staff_surname,
            st.email AS staff_email, ch.id AS channel_id, ch.name AS channel_name,
            ch.network AS channel_network, se.id AS series_id, se.name AS series_name,
            se.count AS series_count
            FROM job_list AS li
            LEFT OUTER JOIN job_staff AS st
            ON li.staff_id = st.id
            LEFT OUTER JOIN job_channel AS ch
            ON li.channel_id = ch.id
            LEFT OUTER JOIN job_series AS se
            ON li.series_id = se.id;";

$result = mysqli_query($dbconnect, $query);

echo "<table border='1'>
<tr>
    <th>Job ID</th>
    <th>Staff ID</th>
    <th>Staff Firstname</th>
    <th>Staff Surname</th>
    <th>Staff E-mail</th>
    <th>Channel ID</th>
    <th>Channel Name</th>
    <th>Channel Network</th>
    <th>Series ID</th>
    <th>Series Name</th>
    <th>Series Count</th>
</tr>";

while($row = mysqli_fetch_array($result))
{
    echo "<tr>";
    echo "<td>" . $row['job_id'] . "</td>";
    echo "<td>" . $row['staff_id'] . "</td>";
    echo "<td>" . $row['staff_firstname'] . "</td>";
    echo "<td>" . $row['staff_surname'] . "</td>";
    echo "<td>" . $row['staff_email'] . "</td>";
    echo "<td>" . $row['channel_id'] . "</td>";
    echo "<td>" . $row['channel_name'] . "</td>";
    echo "<td>" . $row['channel_network'] . "</td>";
    echo "<td>" . $row['series_id'] . "</td>";
    echo "<td>" . $row['series_name'] . "</td>";
    echo "<td>" . $row['series_count'] . "</td>";
    echo "</tr>";
}
echo "</table>";

mysqli_close($dbconnect);

I hope I could illuminate joins a bit. If anything isn't clear yet feel free to ask.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top