How to Oracle SaaS pricing in PostgreSQL

Galaxy Glossary

How do I calculate Oracle-style SaaS pricing tiers with PostgreSQL?

Shows how to store, calculate, and report Oracle-style SaaS subscription pricing tiers with pure PostgreSQL.

Sign up for the latest in SQL knowledge from the Galaxy Team!
Welcome to the Galaxy, Guardian!
You'll be receiving a confirmation email

Follow us on twitter :)
Oops! Something went wrong while submitting the form.

Description

Table of Contents

What is Oracle SaaS pricing and why model it in PostgreSQL?

Oracle SaaS pricing uses subscription terms (monthly, annual), tiered unit prices, and optional discounts. Modeling the logic in PostgreSQL lets engineers run cost simulations, bill customers, and feed dashboards without leaving their data warehouse.

How do I structure tables for tiered SaaS prices?

Create a Products table for list price, a PriceTiers table for quantity-based breaks, and a Subscriptions table that records the customer’s plan, seats, and term.

What SQL calculates the final subscription charge?

Use a CTE to select the matching tier, multiply by quantity, and apply any percent or fixed discount. Wrap it in a calculate_subscription_price() SQL function for reuse.

How do I include one-time setup fees?

Add a setup_fee column to Products. When the function detects a new subscription (no prior invoice), it sums the tiered seat price and the one-time fee.

How can I report MRR and ARR quickly?

Aggregate Subscriptions by term length. For monthly terms divide annualized totals by 12; for annual terms sum the yearly price directly. Use window functions for rolling 3-, 6-, or 12-month trends.

Best practice: store currency amounts in NUMERIC(12,2)

Avoid floating-point rounding by always using NUMERIC for money. Convert to the customer’s display currency only in the UI layer.

Best practice: centralize discounts

Keep a Discounts table keyed by subscription_id. Handling discounts outside the pricing function complicates audits and promotions.

What’s the easiest way to test new pricing tiers?

Insert draft tiers with a valid_from/valid_to range. Point the pricing function to the desired draft date to run "what-if" computations without touching production rows.

Why How to Oracle SaaS pricing in PostgreSQL is important

How to Oracle SaaS pricing in PostgreSQL Example Usage


-- Customer adds 75 seats of "Analytics Cloud" on a monthly term
INSERT INTO Subscriptions (customer_id, product_id, seats, term, discount_pct)
VALUES (1, 3, 75, 'monthly', 10);

-- Calculate first bill
SELECT calculate_subscription_price(id) AS first_month_charge
FROM   Subscriptions
WHERE  customer_id = 1
ORDER  BY id DESC
LIMIT 1;

How to Oracle SaaS pricing in PostgreSQL Syntax


-- Core tables
CREATE TABLE Products (
    id            SERIAL PRIMARY KEY,
    name          TEXT NOT NULL,
    base_price    NUMERIC(12,2) NOT NULL,
    setup_fee     NUMERIC(12,2) DEFAULT 0,
    currency      TEXT DEFAULT 'USD'
);

CREATE TABLE PriceTiers (
    id          SERIAL PRIMARY KEY,
    product_id  INT REFERENCES Products(id),
    min_qty     INT NOT NULL,
    max_qty     INT NOT NULL,
    unit_price  NUMERIC(12,2) NOT NULL,
    valid_from  DATE DEFAULT CURRENT_DATE,
    valid_to    DATE DEFAULT '9999-12-31'
);

CREATE TABLE Customers (
    id SERIAL PRIMARY KEY,
    name TEXT,
    email TEXT,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE Subscriptions (
    id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES Customers(id),
    product_id  INT REFERENCES Products(id),
    seats       INT NOT NULL,
    term        TEXT CHECK (term IN ('monthly','annual')),
    discount_pct NUMERIC(5,2) DEFAULT 0,
    started_at  DATE DEFAULT CURRENT_DATE
);

-- Function to calculate price
CREATE OR REPLACE FUNCTION calculate_subscription_price(p_sub_id INT)
RETURNS NUMERIC(12,2) LANGUAGE plpgsql AS $$
DECLARE
    v_base NUMERIC;
    v_setup NUMERIC;
    v_disc NUMERIC;
BEGIN
    WITH base AS (
        SELECT s.seats, s.discount_pct,
               pt.unit_price, p.setup_fee
        FROM Subscriptions s
        JOIN PriceTiers pt ON pt.product_id = s.product_id
                           AND s.seats BETWEEN pt.min_qty AND pt.max_qty
                           AND CURRENT_DATE BETWEEN pt.valid_from AND pt.valid_to
        JOIN Products p ON p.id = s.product_id
        WHERE s.id = p_sub_id
        LIMIT 1
    )
    SELECT seats * unit_price, setup_fee, discount_pct INTO v_base, v_setup, v_disc FROM base;

    RETURN ROUND((v_base + v_setup) * (1 - v_disc / 100), 2);
END;$$;

Common Mistakes

Frequently Asked Questions (FAQs)

Can I support multiple currencies?

Yes. Add a currency column to Products and store exchange rates in a separate table. Join the rate inside the pricing function to convert on the fly.

How do I bill prorated upgrades?

Record the original invoice amount and seats. When seats increase mid-cycle, compute the new monthly cost, subtract the unused portion of the original amount, and bill the difference.

Is the function performant at scale?

Yes. Index PriceTiers(product_id, min_qty, max_qty) and Subscriptions(product_id). The calculation touches only one product row and one tier row per subscription.

Want to learn about other SQL terms?

Trusted by top engineers on high-velocity teams
Aryeo Logo
Assort Health
Curri
Rubie Logo
Bauhealth Logo
Truvideo Logo
Welcome to the Galaxy, Guardian!
You'll be receiving a confirmation email

Follow us on twitter :)
Oops! Something went wrong while submitting the form.