DEV Community

Cover image for From SQL Query to Product Decision: How SaaS Teams Use Data
Soumabha Mahapatra
Soumabha Mahapatra

Posted on

From SQL Query to Product Decision: How SaaS Teams Use Data

Our trial-to-paid conversion was 4%. One SQL query showed us why.

Most SaaS articles explain what MRR, churn, and activation are. Few show how a team goes from a raw table to a decision that changes the product.

In this post, we'll walk through that journey with a realistic (illustrative) SaaS example, using only SQL and a bit of product thinking.

What you'll learn:

  • How product data flows from a user click to a business decision
  • How to build a funnel, segment users, and measure retention in SQL
  • How to turn a pattern into a product change you can actually test

⚠️ The dataset and numbers in this article are illustrative, created to demonstrate the method. The queries are real and will run on PostgreSQL.


The Problem

Imagine a project-management SaaS called TaskFlow. It offers a 14-day free trial.

In January, 2,000 people signed up for the trial. Only 80 became paying customers.

Trial-to-paid conversion: 80 / 2,000 = 4%

The CEO asks: "Why aren't more trial users paying?"

Opinions fly around: "The pricing is too high." "We need more features." "The emails are bad."

A product analyst's job is to replace opinions with evidence.


The Big Picture: From Click to Decision

Before writing SQL, here is how data moves through a SaaS company:

┌──────────┐   ┌────────────┐   ┌─────────────┐   ┌────────────┐
│   USER   │──▶│  PRODUCT   │──▶│   EVENT     │──▶│ DATABASE / │
│  clicks  │   │  (web app) │   │   TRACKING  │   │ WAREHOUSE  │
└──────────┘   └────────────┘   └─────────────┘   └─────┬──────┘
                                                        │
                                                        ▼
┌──────────┐   ┌────────────┐   ┌─────────────┐   ┌────────────┐
│ DECISION │◀──│  INSIGHT   │◀──│  DASHBOARD  │◀──│  SQL QUERY │
│ & A/B    │   │ "invites   │   │  / CHART    │   │  (analyst) │
│  TEST    │   │  matter"   │   │             │   │            │
└──────────┘   └────────────┘   └─────────────┘   └────────────┘
Enter fullscreen mode Exit fullscreen mode

Every arrow is a place where things can go wrong: missing events, bad joins, misleading charts. The goal is the bottom-left box: a decision.


The Data

We have three simple tables.

CREATE TABLE users (
    user_id             INT PRIMARY KEY,
    signup_date         DATE NOT NULL,
    plan_at_signup      TEXT,           -- 'trial'
    acquisition_channel TEXT            -- 'organic', 'ads', 'referral'
);

CREATE TABLE events (
    event_id    BIGINT PRIMARY KEY,
    user_id     INT REFERENCES users(user_id),
    event_name  TEXT NOT NULL,          -- 'project_created', 'teammate_invited', ...
    event_time  TIMESTAMP NOT NULL
);

CREATE TABLE subscriptions (
    subscription_id INT PRIMARY KEY,
    user_id         INT REFERENCES users(user_id),
    plan            TEXT,               -- 'starter', 'pro'
    mrr             NUMERIC(10,2),
    start_date      DATE NOT NULL,
    cancel_date     DATE                -- NULL = still active
);
Enter fullscreen mode Exit fullscreen mode

Here's how they relate:

 ┌───────────┐ 1      many ┌───────────┐
 │   users   │────────────▶│  events   │
 │-----------│             │-----------│
 │ user_id   │             │ event_id  │
 │ signup_dt │             │ user_id   │
 │ channel   │             │ event_name│
 └─────┬─────┘             │ event_time│
       │ 1                 └───────────┘
       │
       │ 0..1
       ▼
 ┌───────────────┐
 │ subscriptions │
 │---------------│
 │ user_id       │
 │ plan, mrr     │
 │ start/cancel  │
 └───────────────┘
Enter fullscreen mode Exit fullscreen mode

This is a simplified model. Real products also track sessions, pageviews, billing events, and more.


Query 1: Where Do Users Drop Off? (The Funnel)

Funnel analysis is the first thing to run when conversion is low. It shows where users leave.

WITH cohort AS (
    SELECT user_id
    FROM users
    WHERE signup_date >= '2026-01-01'
      AND signup_date <  '2026-02-01'
)
SELECT
    COUNT(DISTINCT c.user_id) AS signed_up,
    COUNT(DISTINCT CASE WHEN e.event_name = 'project_created'
                        THEN c.user_id END) AS created_project,
    COUNT(DISTINCT CASE WHEN e.event_name = 'teammate_invited'
                        THEN c.user_id END) AS invited_teammate,
    COUNT(DISTINCT s.user_id)               AS converted_to_paid
FROM cohort c
LEFT JOIN events        e ON e.user_id = c.user_id
LEFT JOIN subscriptions s ON s.user_id = c.user_id;
Enter fullscreen mode Exit fullscreen mode

Result:

Funnel Step Users % of Signups Drop-off from Previous
Signed up 2,000 100% n/a
Created a project 1,300 65% -35%
Invited a teammate 380 19% -71%
Converted to paid 80 4% -79%

The same data as a chart:

FUNNEL: January trial cohort (2,000 users)

Signed up          ████████████████████████████████████████  2,000 (100%)
Created project    ██████████████████████████                1,300 (65%)
Invited teammate   ████████                                    380 (19%)
Paid               ██                                           80 (4%)
Enter fullscreen mode Exit fullscreen mode

What we notice: The biggest cliff is between creating a project and inviting a teammate. Most users start the product alone and never bring anyone else in.

That's a hypothesis, not a conclusion. Let's test it.


Query 2: Do Users Who Invite a Teammate Convert Better?

We'll split users into two segments:

  • Early inviters: invited a teammate within 3 days of signing up
  • Everyone else
WITH first_invite AS (
    SELECT
        u.user_id,
        u.signup_date,
        MIN(e.event_time) AS invited_at
    FROM users u
    LEFT JOIN events e
           ON e.user_id = u.user_id
          AND e.event_name = 'teammate_invited'
    WHERE u.signup_date >= '2026-01-01'
      AND u.signup_date <  '2026-02-01'
    GROUP BY u.user_id, u.signup_date
)
SELECT
    CASE
        WHEN f.invited_at <= f.signup_date + INTERVAL '3 days'
            THEN 'invited_within_3_days'
        ELSE 'did_not_invite_early'
    END AS segment,
    COUNT(*)                                        AS users,
    COUNT(s.user_id)                                AS paid_users,
    ROUND(100.0 * COUNT(s.user_id) / COUNT(*), 1)   AS conversion_pct
FROM first_invite f
LEFT JOIN subscriptions s ON s.user_id = f.user_id
GROUP BY 1
ORDER BY conversion_pct DESC;
Enter fullscreen mode Exit fullscreen mode

Result:

Segment Users Paid Users Conversion
invited_within_3_days 300 60 20.0%
did_not_invite_early 1,700 20 1.2%
CONVERSION RATE BY SEGMENT

Invited within 3 days   ████████████████████  20.0%
Did not invite early    █                      1.2%
                        └────────────────────────────
                        0%        10%        20%
Enter fullscreen mode Exit fullscreen mode

Early inviters convert about 17x better. This is the strongest signal in the data so far.


Query 3: Do They Also Stay Longer? (Retention)

Conversion is only half the story. A customer who cancels in month two isn't worth much. Let's check 90-day churn among paying customers, by segment.

WITH first_invite AS (
    SELECT
        u.user_id,
        u.signup_date,
        MIN(e.event_time) AS invited_at
    FROM users u
    LEFT JOIN events e
           ON e.user_id = u.user_id
          AND e.event_name = 'teammate_invited'
    WHERE u.signup_date >= '2026-01-01'
      AND u.signup_date <  '2026-02-01'
    GROUP BY u.user_id, u.signup_date
),
segmented AS (
    SELECT
        f.user_id,
        CASE
            WHEN f.invited_at <= f.signup_date + INTERVAL '3 days'
                THEN 'invited_within_3_days'
            ELSE 'did_not_invite_early'
        END AS segment
    FROM first_invite f
)
SELECT
    sg.segment,
    COUNT(*) AS paying_customers,
    COUNT(*) FILTER (
        WHERE s.cancel_date IS NOT NULL
          AND s.cancel_date <= s.start_date + 90
    ) AS churned_within_90d,
    ROUND(100.0 * COUNT(*) FILTER (
        WHERE s.cancel_date IS NOT NULL
          AND s.cancel_date <= s.start_date + 90
    ) / COUNT(*), 1) AS churn_90d_pct
FROM segmented sg
JOIN subscriptions s ON s.user_id = sg.user_id
GROUP BY sg.segment;
Enter fullscreen mode Exit fullscreen mode

Result:

Segment Paying Customers Churned in 90 Days 90-Day Churn
invited_within_3_days 60 5 8.3%
did_not_invite_early 20 7 35.0%
90-DAY CUSTOMER RETENTION (illustrative)

Invited early      ██████████████████████████████████████  91.7% retained
Did not invite     ██████████████████████████              65.0% retained
                   └─────────────┬─────────────┬─────────
                                50%          100%
Enter fullscreen mode Exit fullscreen mode

Teams that invite colleagues convert more and stay longer. This makes sense: once a whole team's workflow lives in your product, switching is painful.


The Insight

Putting the three queries together:

Question Query Finding
Where do users drop off? Funnel Most never invite a teammate (only 19% do)
Does inviting help conversion? Segment 20.0% vs 1.2% conversion
Does inviting help retention? Churn 8.3% vs 35.0% 90-day churn

Insight: Inviting a teammate within the first 3 days is a strong indicator of both conversion and retention. Only 15% of users (300 of 2,000) do it.


A Word of Caution: Correlation ≠ Causation

Before celebrating, ask honestly: does inviting a teammate cause conversion, or are teams that were already serious just more likely to invite?

Possibly both. Here are other things to check:

  • Sample size: only 20 paying customers are in the "did not invite" group. That's small, so treat the churn numbers as directional.
  • Selection bias: motivated users do more of everything.
  • Confounders: maybe larger companies both invite more and pay more. Segment by channel or company size.

The correct way to settle this is an experiment, not another query.


From Insight to Decision

The team decides to test the hypothesis: "If we push more users to invite a teammate early, conversion will improve."

Step Action
1 Add "Invite your team" as a step in the onboarding checklist
2 Show a prompt after the first project is created
3 Send a day-2 email: "Projects work better with your team"
4 A/B test: 50% see the new onboarding, 50% see the old one
5 Measure: early-invite rate, trial-to-paid conversion, 90-day churn
          ALL NEW TRIAL USERS
                  │
        ┌─────────┴─────────┐
        ▼                   ▼
  CONTROL (50%)       VARIANT (50%)
  Old onboarding      New onboarding
                      + invite prompt
        │                   │
        ▼                   ▼
   Measure early-invite rate, conversion, churn
                  │
                  ▼
         Ship, iterate, or roll back
Enter fullscreen mode Exit fullscreen mode

Illustrative Experiment Results (4 weeks)

Metric Control Variant Change
Users in group 1,000 1,000
Invited within 3 days 15.0% 27.0% +12.0 pts
Trial-to-paid conversion 4.0% 6.1% +2.1 pts
TRIAL-TO-PAID CONVERSION

Control   ████████            4.0%
Variant   ████████████        6.1%
Enter fullscreen mode Exit fullscreen mode

A lift from 4.0% to 6.1% is about a 52% relative improvement. If the product has 2,000 trials per month and an average MRR of $30 per customer, that's roughly 42 extra customers per month, or about $1,260 in new MRR every month.

(Before shipping, you'd also run a significance test and confirm the retention effect holds. Don't skip this step.)


The Framework You Can Reuse

This pattern works for almost any SaaS question:

1. OBSERVE      →  A metric looks wrong (low conversion)
2. LOCATE       →  Funnel query: where is the drop-off?
3. SEGMENT      →  Compare behaviors of converters vs non-converters
4. VALIDATE     →  Check retention, sample size, and confounders
5. HYPOTHESIZE  →  "If we change X, metric Y will improve"
6. TEST         →  A/B test it
7. DECIDE       →  Ship, iterate, or kill
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Start with a business question, not a query. "Why is conversion low?" beats "Let me explore the events table."
  • Funnels find the problem; segmentation finds the cause.
  • Look at conversion and retention. A win on one can hide a loss on the other.
  • Be skeptical of your own insight. Check sample size, bias, and confounders.
  • Queries give you hypotheses; experiments give you proof.
  • The output of analytics is a decision, not a dashboard.

Try It Yourself

  1. Spin up a free PostgreSQL instance (local, Docker, or Supabase)
  2. Create the three tables above
  3. Generate sample data with a script (Python + Faker works well)
  4. Run the queries and tweak the segments: invites within 1 day? 7 days? by channel?

If you build your own version, I'd love to see it. Share your queries or findings in the comments!


What's the most surprising insight you've found hiding in your product data? Let me know below. 👇

Top comments (0)