CYBERTEC PostgreSQL Logo

PostgreSQL: To normalize or not to normalize?

03.2025 / Category: / Tags:

The concept of "normalization" is often the first thing people who are new to databases are going to learn. We are talking about one of the fundamental principles in the realm of databases. But what is the use of normalization in the first place? Well, we want to avoid redundancies in the data and make sure that information is stored in a way that helps reduce mistakes and inconsistencies. Ultimately, that is all there is to it: No redundancies, no mistakes, no inconsistencies.

Normalization in action

Before we dive into more detail, we will first take a look at a simple example of a normalized table in PostgreSQL. The purpose of the following data structure is to store products and categories:

The goal here is to store each piece of information only once. Here, this means that the name of the product category is only mentioned one time. "Shoes" and "Plants" do not show up in the product table - instead, we only store the ID. The advantage of this is that we can rename a category without having to modify those products.

A join will reveal the content of our two simple tables:

So far, normalization has only been one more concept in the vast ocean of ideas. However, it starts to be relevant as soon as we update categories:

It is important to note here that we have changed data in a single place and consequently affected multiple rows without ever touching them. This gives us something of great importance: Consistency and integrity.

Is there "too much normalization"?

Normalization sounds like some “holy grail”; however, as with everything in life, there are usually no simple answers to blindly be applied to all problems. The same is true for normalization. But when is this the case? When is over-normalization essentially a bug?

Consider the following example:

What is the problem here? We have created a table that stores invoices. It contains a listing of products we have sold.

Let us see what happens:

In this example we imagine that we sold shoes twice in the past. What we want to do next is to pull a report and figure out how much turnover we have.

Here is how it works:

We made a stunning amount of 1344.39 Postgres bucks. But what is the problem? Remember, we used a foreign key to link the sales table to the product table. As is revealed by the following list, this was a big mistake:

In case the prices of the products change, we find ourselves with destroyed data. The problem is that we aren’t interested in the current price of the product - for a report we need the data as it was back when we sold those shoes. In case of full normalization we have made a major mistake destroying vital sales statistics.

Storing information correctly

The question naturally arising is: What is the better way to store this type of data? What we have to do is to redundantly store data as its value at the time of sale.

Here is how we might want to store the data:

The name of the product as well as the price have to be fields in the table to avoid changing data later on. It might happen that products are removed, or that prices as well as names are changed. We have to reflect this in our tables containing historic data.

As simple as it sounds: This type of mistake often happens in various applications and developers have to be aware of those issues when designing proper data structures (especially when generative AI is used to create table definitions).

Read more about "normalization" in other blog postings:

Data Normalization in PostgreSQL
Practical Examples of Data Normalization in PostgreSQL

Leave a Reply

Your email address will not be published. Required fields are marked *

CYBERTEC Logo white
Get the newest PostgreSQL Info & Tools


    This site is protected by reCAPTCHA and the Google Privacy Policy & Terms of Service apply.

    ©
    2025
    CYBERTEC PostgreSQL International GmbH
    phone-handsetmagnifiercrosscross-circle
    linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram