Skip to content

Cleaning a PostgreSQL Database

In this project, you will work with data from a hypothetical Super Store to challenge and enhance your SQL skills in data cleaning. This project will engage you in identifying top categories based on the highest profit margins and detecting missing values, utilizing your comprehensive knowledge of SQL concepts.

Data Dictionary:

orders:

ColumnDefinitionData typeComments
row_idUnique Record IDINTEGER
order_idIdentifier for each order in tableTEXTConnects to order_id in returned_orders table
order_dateDate when order was placedTEXT
marketMarket order_id belongs toTEXT
regionRegion Customer belongs toTEXTConnects to region in people table
product_idIdentifier of Product boughtTEXTConnects to product_id in products table
salesTotal Sales Amount for the Line ItemDOUBLE PRECISION
quantityTotal Quantity for the Line ItemDOUBLE PRECISION
discountDiscount applied for the Line ItemDOUBLE PRECISION
profitTotal Profit earned on the Line ItemDOUBLE PRECISION

returned_orders:

ColumnDefinitionData type
returnedYes values for Order / Line Item ReturnedTEXT
order_idIdentifier for each order in tableTEXT
marketMarket order_id belongs toTEXT

people:

ColumnDefinitionData type
personName of Salesperson credited with OrderTEXT
regionRegion Salesperson in operating inTEXT

products:

ColumnDefinitionData type
product_idUnique Identifier for the ProductTEXT
categoryCategory Product belongs toTEXT
sub_categorySub Category Product belongs toTEXT
product_nameDetailed Name of the ProductTEXT

As you can see in the Data Dictionary above, date fields have been written to the orders table as TEXT and numeric fields like sales, profit, etc. have been written to the orders table as Double Precision. You will need to take care of these types in some of the queries. This project is an excellent opportunity to apply your SQL skills in a practical setting and gain valuable experience in data cleaning and analysis. Good luck, and happy querying!

Spinner
DataFrameas
top_five_products_each_category
variable
-- Goal: Top_five_products_each_by_category
-- Subquery to rank products in each category
SELECT * FROM (
  -- Select category, product name, total sales, total profit, and rank products
  SELECT products.category, 
    products.product_name,
    ROUND(SUM(CAST(ord.sales AS NUMERIC)), 2) AS product_total_sales,
    ROUND(SUM(CAST(ord.profit AS NUMERIC)), 2) AS product_total_profit,
    RANK() OVER(PARTITION BY products.category ORDER BY SUM(ord.sales) DESC) AS product_rank
  FROM orders AS ord
  INNER JOIN products
    ON ord.product_id = products.product_id
  GROUP BY products.category, products.product_name
) AS tmp
-- Filter to get the top 5 products in each category
WHERE product_rank < 6;

Spinner
DataFrameas
df
variable
-- Select missing values
  SELECT product_id,
    discount, 
    market,
    region,
    sales,
    quantity
  FROM orders 
  WHERE quantity IS NULL;
Spinner
DataFrameas
df1
variable
-- Calculate unit prices for products with non-NULL quantity
  SELECT o.product_id,
    CAST(o.sales / o.quantity AS NUMERIC) AS unit_price
  FROM orders o
  WHERE o.quantity IS NOT NULL;
Spinner
DataFrameas
impute_missing_values
variable
-- Goal: Impute missing values

-- Create a CTE to select products with NULL quantity
WITH missing AS (
  SELECT product_id,
    discount, 
    market,
    region,
    sales,
    quantity
  FROM orders 
  WHERE quantity IS NULL
),

-- Create a CTE to calculate unit prices for products with non-NULL quantity
unit_prices AS (
  SELECT o.product_id,
    CAST(o.sales / o.quantity AS NUMERIC) AS unit_price
  FROM orders o
-- Perform RIGHT JOIN to ensure all rows from 'missing' are included
  RIGHT JOIN missing AS m 
    ON o.product_id = m.product_id
    AND o.discount = m.discount
  WHERE o.quantity IS NOT NULL
)

-- Select rows from 'missing' and calculate the missing quantities
SELECT DISTINCT m.*,
  ROUND(CAST(m.sales AS NUMERIC) / up.unit_price, 0) AS calculated_quantity
FROM missing AS m
INNER JOIN unit_prices AS up
  ON m.product_id = up.product_id;

Spinner
DataFrameas
products
variable
SELECT * FROM public.products
Spinner
DataFrameas
df2
variable
SELECT * FROM orders where quantity is null;