Article

Create MySQL Lookup Tables with PHP on Ubuntu 20.04

Author: Francis Ndungu

Last Updated: Sat, Feb 20, 2021
MySQL and MariaDB

Introduction

A lookup table is an array of items for users to select from your application when submitting data to your server. Normally, the lookup table list is used when collecting data with HTML forms and is considered a good design practice when creating applications. For instance, when designing a customer registration form, you might create a list box with MALE and FEMALE values. In that case, end-users are forced to select an item only from the pre-defined items. This is a good method that you can incorporate in your project to enforce data validation rules without too much coding.

Lookup tables are also great when it comes to saving storage in your database. Imagine a scenario where you've millions of subscribers in your database. It would take less space to keep their genders as integers values instead of strings for such a significant number. You don't want a design pattern that bloats your database. When the data stored in your database is small, processing also becomes more manageable. This improves your application's performance, especially when you index referenced columns in the child tables, which are tables referencing columns back to the lookup tables.

Another great advantage is data modification and the ease of maintaining your code. For instance, if you have a lookup table for countries and want to change the value of USA to USA - NORTH AMERICA, you don't need to change the code. You change the lookup table's value, and changes will be propagated in connected forms when users refresh their browsers. Lookup tables are also great when it comes to maintaining additional information related to the option values. Consider a case where you're offering three packages for customers subscribing to your online products. Instead of just displaying the plans' name, you can code your list boxes to display your products alongside the prices to allow customers to make a better decision.

In this tutorial, you'll create a sample test_company database, create some lookup tables and incorporate them later in the guide to collect and submit customers' data from HTML forms with PHP on Ubuntu 20.04.

Prerequisites

Before you begin, ensure that you have the following:

Create a test_company Database

Begin by connecting to your server and log in to MySQL as a root.

$ sudo mysql -u root -p

Enter the root password of your MySQL server and hit ENTER to continue. Next, run the command below to create a test_company database.

mysql> CREATE DATABASE test_company;

Use the test_company database.

mysql> USE test_company;

Next, create a test_user as it is not recommended to use the root user's credentials in the PHP scripts for security purposes. Remember to replace EXAMPLE_PASSWORD with a strong value.

mysql> CREATE USER 'test_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'EXAMPLE_PASSWORD';
mysql> GRANT ALL PRIVILEGES ON test_company.* TO 'test_user'@'localhost';
mysql> FLUSH PRIVILEGES;

In case you've installed MariaDB instead of MySQL in your server, use the code below to create the test_user account.

MariaDB> GRANT ALL PRIVILEGES on test_company.* TO 'test_user'@'localhost' identified by 'EXAMPLE_PASSWORD';

Create plans Lookup Table

In this tutorial, you'll assume that you're offering 3 plans for your products to anyone who subscribes to your online database. However, you might consider adding more plans in the future as you get more customers to cater to their future demands.

Instead of hard-coding these plans to an HTML form, you'll create a flexible MySQL lookup table with all the plans you intend to offer. The good thing about this approach is flexibility. After you've created the table, you can add as many plans as you want, and you can even alter the names in the future without changing your PHP code.

Create the plans table.

mysql> CREATE TABLE plans (
       plan_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
       plan_name  VARCHAR(50),
       price  DECIMAL(17,2)
       ) ENGINE = InnoDB;

Next, insert some records into the plans table.

mysql> INSERT INTO plans (plan_name, price) VALUES ('BASIC', '5.00');
mysql> INSERT INTO plans (plan_name, price) VALUES ('DEDICATED', '15.00');
mysql> INSERT INTO plans (plan_name, price) VALUES ('PROFESSIONAL', '50.00');

Query the plans table to ensure that your records are in place.

mysql> SELECT
       plan_id,
       plan_name,
       price
       FROM plans;

You should now see a list of plans as shown below.

+---------+--------------+-------+
| plan_id | plan_name    | price |
+---------+--------------+-------+
|       1 | BASIC        |  5.00 |
|       2 | DEDICATED    | 15.00 |
|       3 | PROFESSIONAL | 50.00 |
+---------+--------------+-------+
3 rows in set (0.00 sec)

Create countries Lookup Table

Next, you'll create a countries table. In your hypothetical company, you might get customers from different countries. However, due to your preferences or laws governing your countries, you might restrict customers' registration only to a few countries. New subscribers who miss their country name from the list won't register for your product. This is one way that you can use lookup tables to enforce validation rules in your application.

Execute the command below to create the countries table.

mysql> CREATE TABLE countries (
       country_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
       country_name  VARCHAR(50)
       ) ENGINE = InnoDB;

Next, populate the countries table with some records.

mysql> INSERT INTO countries (country_name) VALUES ('USA');
mysql> INSERT INTO countries (country_name) VALUES ('KENYA');
mysql> INSERT INTO countries (country_name) VALUES ('GERMANY');

Query the countries table to make sure it was populated.

mysql> SELECT
       country_id,
       country_name
       FROM countries;

Ensure you get the list of countries as shown below.

+------------+--------------+
| country_id | country_name |
+------------+--------------+
|          1 | USA          |
|          2 | KENYA        |
|          3 | GERMANY      |
+------------+--------------+
3 rows in set (0.00 sec)

Create genders Lookup Table

The most common genders of subscribers are MALE and FEMALE. But just like in the plans and countries, you don't have to hard-code this in your PHP scripts. This is because you might need to incorporate more gender options in the future. Using a MySQL lookup table, adding new genders will be as simple as inserting a new record into the genders table without touching the base PHP code.

To put this into a better perspective, if there are customers who don't want to disclose their gender during registration, you may later consider adding a new option in the lookup table like, I'd rather not say my gender.

Run the below command to create the genders table.

mysql> CREATE TABLE genders (
       gender_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
       gender_name  VARCHAR(50)
       ) ENGINE = InnoDB;

Add the MALE and the FEMALE genders into the table.

mysql> INSERT INTO genders (gender_name) VALUES ('MALE');
mysql> INSERT INTO genders (gender_name) VALUES ('FEMALE');

Query the table to make sure the table is populated.

mysql> SELECT
       gender_id,
       gender_name
       FROM genders;

You should now see 2 genders as shown below.

+-----------+-------------+
| gender_id | gender_name |
+-----------+-------------+
|         1 | MALE        |
|         2 | FEMALE      |
+-----------+-------------+
2 rows in set (0.00 sec)

Create a customers Table

The last object to create in your test_company database is the customers table. This table will store customers' names together with their personal information, including their gender, country, and preferred plans.

In this table, the customers' gender, country, and plan will be represented by indexed INTEGER values related to the base lookup tables.

For instance, if a customer gender is MALE, the gender_id column in the customers table will be represented by 1. Remember if you query the genders table 1 corresponds to MALE.

The same case also applies to the countries. Instead of entering the country's string value in the customers table, the country_id from the countries lookup table is used.

Create the customers table by running the command below.

mysql> CREATE TABLE customers (
       customer_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
       first_name  VARCHAR(50),
       last_name  VARCHAR(50),
       gender_id  INT,
       address  VARCHAR(50),
       country_id  INT,
       plan_id  INT,
       INDEX (gender_id),
       FOREIGN KEY (gender_id) REFERENCES genders (gender_id),
       INDEX (country_id),
       FOREIGN KEY (country_id) REFERENCES countries (country_id),
       INDEX (plan_id),
       FOREIGN KEY (plan_id) REFERENCES plans (plan_id)
       ) ENGINE = InnoDB;

In the command above, all columns that refer back to lookup tables have been indexed and defined with the FOREIGN KEY constraints to enforce referential integrity in your data.

Don't enter any record into the customers table. You're going to code an HTML form to enter customers' information to the table.

Exit from the MySQL command-line interface.

mysql> QUIT;

Create the HTML Form

Create a /var/www/html/html_form.php file.

$ sudo nano /var/www/html/html_form.php

Then enter the information below into the file.

<html>
  <body>
    <?php
        try {
            define('DB_NAME', 'test_company');
            define('DB_USER', 'test_user');
            define('DB_PASSWORD', 'EXAMPLE_PASSWORD');
            define('DB_HOST', 'localhost');

            $pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER , DB_PASSWORD );
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

            $stmt = $pdo->prepare("SELECT * FROM genders");
            $stmt->execute();
            $genders = $stmt->fetchAll();

            $stmt = $pdo->prepare("SELECT * FROM countries");
            $stmt->execute();
            $countries = $stmt->fetchAll();

            $stmt = $pdo->prepare("SELECT * FROM plans");
            $stmt->execute();
            $plans = $stmt->fetchAll();
            } catch(PDOException $e) {
                echo $e->getMessage();
            }
    ?>

    <h2>Registration Form</h2>
      <form action="register.php" method="post">

        <label for="first_name">First name:</label><br>
        <input type="text" id="first_name" name="first_name"><br><br>

        <label for="last_name">Last name:</label><br>
        <input type="text" id="last_name" name="last_name"><br><br>

        <label for="gender_id">Choose your gender</label><br>
        <select name="gender_id" id="gender_id">
        <?php
            foreach ($genders as $gender) {
                echo '<option value=' . $gender['gender_id'] . '>' . $gender['gender_name'] . '</option>';
            }
        ?>
        </select><br><br>

        <label for="address">Address:</label><br>
        <input type="text" id="address" name="address"><br><br>
        <label for="country_id">Choose your country</label><br>
        <select name="country_id" id="country_id">
        <?php
            foreach ($countries as $country) {
                echo '<option value=' . $country['country_id'] . '>' . $country['country_name'] . '</option>';
            }
        ?>
        </select><br><br>

        <label for="plan_id">Choose your Plan</label><br>
        <select name="plan_id" id="plan_id">
        <?php
            foreach ($plans as $plan) {
                echo '<option value=' . $plan['plan_id'] . '>' . $plan['plan_name'] . '</option>';
            }
        ?>
        </select><br><br>

        <input type="submit" value="Register">
      </form>
  </body>
</html>

Save and close the file.

At the top of the /var/www/html/html_form.php file, you're connecting to the database that you created earlier. Then, you're executing an SQL statement to retrieve values from each lookup table and placing them in an array. For instance, you're using the genders array to store lookup gender names and their corresponding gender ids temporarily.

...
$stmt = $pdo->prepare("SELECT * FROM genders");
$stmt->execute();
$genders = $stmt->fetchAll();
...

Then, you're looping through the array items to display these values as list options.

...
<?php
    foreach ($genders as $gender) {
        echo '<option value=' . $gender['gender_id'] . '>' . $gender['gender_name'] . '</option>';
    }
?>
...

You've repeated this logic for all list boxes to retrieve their corresponding values from the MySQL lookup tables that you created earlier.

When designing the form, you've telling PHP to process it using a file named register.php because you've added this value inside the form opening tags.

<form action="register.php" method="post">

Create a Backend Process for the Form

In this step, you'll create the PHP registration script. The code in this file will take the values collected from the HTML form you've designed above and execute an INSERT statement to populate the customers table.

Create the registration file /var/www/html/register.php.

$ sudo nano /var/www/html/register.php

Then, enter the information below into the file.

<?php
    try {
        define('DB_NAME', 'test_company');
        define('DB_USER', 'test_user');
        define('DB_PASSWORD', 'EXAMPLE_PASSWORD');
        define('DB_HOST', 'localhost');

        $pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER , DB_PASSWORD );
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

        $sql = "INSERT INTO customers
               (
               first_name,
               last_name,
               gender_id,
               address,
               country_id,
               plan_id
               )
               VALUES
               (
               :first_name,
               :last_name,
               :gender_id,
               :address,
               :country_id,
               :plan_id
               )";

        $data = [
                'first_name' => $_POST['first_name'],
                'last_name'  => $_POST['last_name'],
                'gender_id'  => $_POST['gender_id'],
                'address'    => $_POST['address'],
                'country_id' => $_POST['country_id'],
                'plan_id'    => $_POST['plan_id']
                ];

        $stmt = $pdo->prepare($sql);
        $stmt->execute($data);

        echo "You have been successfully registered into the database.";

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

Save and close the file. The above code connects to the database, prepares an INSERT statement using named parameters(to prevent SQL injection), and then submits collected data into the customers table.

Please note, this code is for demonstration purposes only. Although it uses parameterized queries for security purposes, you might need to add a step to sanitize the data further against known attack vectors in a production environment. For instance, if you're expecting an integer for a value, make sure this is the supplied value.

Test the Form and the Registration Script

The next step is testing the form to see if everything is working. Visit the URL below on a web browser. Remember to replace your_server_public_ip_address with the public IP address or domain name of your server.

http://your_server_public_ip_address/html_form.php

After you get the HTML form, populate it with some data, as shown below.

Registration Form

Then, click the Register button to submit the form. You'll get a success message that your details have been submitted.

You have been successfully registered into the database.

To ensure that the details have been saved into the customers table, get back to your MySQL command-line interface.

$ sudo mysql -u root -p

Use the test_company database.

mysql> USE `test_company`;

Execute the SELECT statement below.

mysql> SELECT
       customer_id,
       first_name,
       last_name,
       gender_id,
       address,
       country_id,
       plan_id
       FROM customers;

You should now see one record in the customers list.

+-------------+------------+-----------+-----------+---------+------------+---------+
| customer_id | first_name | last_name | gender_id | address | country_id | plan_id |
+-------------+------------+-----------+-----------+---------+------------+---------+
|           1 | JOHN       | DOE       |         1 | 111     |          1 |       2 |
+-------------+------------+-----------+-----------+---------+------------+---------+
1 row in set (0.00 sec)

Changing the Values of Lookup Tables

Finally, you'll change some lookup table values and see if the HTML form reflects this change.

First, add a new product to the plans table by running the below query in the MySQL command-line interface.

mysql> INSERT INTO plans (plan_name, price) VALUES ('EXECUTIVE', '75.00');

Next, update the countries table to include the names of the continents.

mysql> UPDATE countries SET
       country_name = 'USA - NORTH AMERICA'
       where country_id = 1;

mysql> UPDATE countries SET
       country_name = 'KENYA - AFRICA'
       where country_id = 2;

mysql> UPDATE countries SET
       country_name = 'GERMANY - EUROPE'
       where country_id = 3;

Also, for customers who don't want to disclose their gender information during registration, add a new option for them.

mysql> INSERT INTO genders (gender_name) VALUES ('I WOULD RATHER NOT SAY');

Visit the HTML form page html_form.php and see if the changes have been reflected. If the address is still open in your browser window, refresh it.

http://your_server_public_ip_address/html_form.php

You should now see the modified form picking up the new list from the lookup tables as shown below.

Modified Registration Form

The changes in the screenshot above have been highlighted for better viewing. Choose the values below and submit the form again.

New Form values

Again, you should get a success message.

You have been successfully registered into the database.

Confirm the changes again from the customers table.

mysql> SELECT
       customer_id,
       first_name,
       last_name,
       gender_id,
       address,
       country_id,
       plan_id
       FROM customers;

You should now have a list with two records.

+-------------+------------+-----------+-----------+---------+------------+---------+
| customer_id | first_name | last_name | gender_id | address | country_id | plan_id |
+-------------+------------+-----------+-----------+---------+------------+---------+
|           1 | JOHN       | DOE       |         1 | 111     |          1 |       2 |
|           2 | MARY       | ROE       |         3 | 222     |          3 |       4 |
+-------------+------------+-----------+-----------+---------+------------+---------+
2 rows in set (0.00 sec)

When querying the child table customers, you can only view lookup value ids or magic numbers, which are values that should be given a symbolic name.

To spell out these magic numbers, use a MySQL JOIN statement to retrieve the lookup ids' actual names using the command below.

mysql> SELECT
       customer_id,
       first_name,
       last_name,
       customers.gender_id,
       gender_name,
       address,
       customers.country_id,
       country_name,
       customers.plan_id,
       plan_name
       FROM customers
       LEFT JOIN plans
       ON customers.plan_id = plans.plan_id
       LEFT JOIN countries
       ON customers.country_id = countries.country_id
       LEFT JOIN genders
       ON customers.gender_id = genders.gender_id;

You should get a nice output displaying the customers' list and the actual string values for the magic numbers.

+-------------+------------+-----------+-----------+------------------------+---------+------------    +---------------------+---------+-----------+
| customer_id | first_name | last_name | gender_id | gender_name            | address | country_id | country_name            | plan_id | plan_name |
+-------------+------------+-----------+-----------+------------------------+---------+------------    +---------------------+---------+-----------+
|           1 | JOHN       | DOE       |         1 | MALE                   | 111     |          1 | USA - NORTH AMERICA     |       2 | DEDICATED |
|           2 | MARY       | ROE       |         3 | I WOULD RATHER NOT SAY | 222     |          3 | GERMANY - EUROPE        |       4 | EXECUTIVE |
+-------------+------------+-----------+-----------+------------------------+---------+------------    +---------------------+---------+-----------+
2 rows in set (0.00 sec)

Conclusion

In this tutorial, you've learned how to create MySQL lookup tables and incorporate them when designing applications with PHP on Ubuntu 20.04. Feel free to use and extend the code in this guide to suit your use-case.

Want to contribute?

You could earn up to $600 by adding new articles