Back to Blog
Lesson 5 of the PostgreSQL: SQL & PostgreSQL from Scratch course
DatabasesJuly 16, 20264 min read

Building the Customers Table: A Practical Guide to SQL Schema

Learn to build a robust customers table in PostgreSQL. Master data types, field selection, and column constraints to ensure clean, reliable user data.

PostgreSQLSQLDatabasesSchemaData Modeling
Black and white photo of a craftsman working on a laptop in a workshop setting.

Previously in this course, we covered the foundational concepts of designing the products table using SQL DDL. In this lesson, we shift our focus to the human side of our store application by building a customers table to store profile information.

A well-structured table is the difference between an application that "just works" and one that handles real-world data gracefully. We will define the essential fields for a customer, choose the correct PostgreSQL data types for text and contact information, and apply constraints to ensure our data remains accurate.

Defining Customer Fields and Data Types

When designing a schema, you must choose data types that accurately represent your data while minimizing storage overhead. For a customers table, we generally need fields for identity, names, and contact details.

Here is the breakdown of our field selection:

  • id: We will use a numeric identifier (this will become a Primary Key in later lessons).
  • first_name & last_name: We use the VARCHAR type. VARCHAR(n) is ideal for names as it enforces a maximum length, which is a simple way to prevent excessively long strings from polluting your database.
  • email: We use VARCHAR(255). It is important to leave enough room for long email addresses while keeping the column bounded.
  • phone: Even though phone numbers consist of digits, we store them as VARCHAR. This prevents issues with leading zeros (e.g., 091...) and allows for optional formatting characters like +, -, or ().

Implementing the Customers Table

Positive young Asian waitress in apron and hat serving delicious pasta for interested diverse female customers in cozy cafe

Let's put this into practice. Open your SQL editor (or psql) connected to your store database and execute the following statement:

SQL
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    email VARCHAR(255) NOT NULL,
    phone VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Understanding the Constraints

In the code above, we introduced three critical concepts:

  1. SERIAL: This automatically handles incrementing the ID for every new customer. It ensures every row has a unique identifier without you having to manually manage the counter.
  2. NOT NULL: By marking first_name, last_name, and email as NOT NULL, we tell PostgreSQL to reject any row insertion that lacks these essential values. This is your first line of defense against "dirty" data.
  3. DEFAULT CURRENT_TIMESTAMP: This automatically populates the created_at field with the exact time the row was inserted, providing an audit trail for your users.

Hands-on Exercise

Now it's your turn to expand the schema.

Task: Modify your customers table (or create a new one called customers_v2 for practice) to include a mailing_address field.

  • Requirement: Use a TEXT data type, as addresses vary significantly in length.
  • Challenge: Add a constraint to ensure the email field is unique, preventing the same user from registering multiple times with the same address. (Hint: Add UNIQUE after the VARCHAR(255) definition for the email column).

Common Pitfalls to Avoid

Text cubes spelling 'DON'T' on a clean white background, ideal for concepts of caution or prohibition.

  • Over-constraining field lengths: While VARCHAR(10) might seem sufficient for a first name, it will fail for names like "Christopher" or international names. Always provide a generous buffer (like 100).
  • Using INT for phone numbers: Never store phone numbers as integers. You will lose leading zeros and be unable to store international country codes that start with +.
  • Ignoring NULLs: If a field is required for your business logic (like an email address), always define it as NOT NULL. Relying on application-side validation is risky; database-level constraints are your final safety net.

Frequently Asked Questions

Q: Should I use CHAR or VARCHAR for names? A: Always use VARCHAR. CHAR is a fixed-length type; if you define CHAR(100) and store "John", PostgreSQL will pad the remaining 96 spaces with blanks, wasting storage.

Q: Is TEXT better than VARCHAR? A: In modern PostgreSQL, there is no performance difference between TEXT and VARCHAR. Use VARCHAR(n) when you want to enforce a specific business limit (like a name length), and use TEXT for open-ended fields like addresses or bio descriptions.

Q: Can I change these constraints later? A: Yes. As you learn more about defining entities and attributes in data modeling, you may find the need to alter tables. PostgreSQL makes it easy to add or drop constraints using ALTER TABLE commands.

Recap

Wooden Scrabble tiles spelling 'RECAP' on a brown textured background. Text concept image.

In this lesson, we established the foundation for user management by creating a customers table. We selected appropriate data types like VARCHAR for strings and SERIAL for IDs, while using NOT NULL constraints to ensure high-quality, reliable data. These schema-level guardrails ensure your application remains stable as you scale.

Up next: We will begin retrieving the data we've stored by mastering the basics of SELECT queries.

Similar Posts