Recipe Tableau and SQL
How many of this month's customers are new, and how many came back?
Find each customer's first order date with { FIXED [customer_id] : MIN([order_date]) }, then compare every order's month to it: same month is new, a later month is returning. In this plant shop, new customers outnumber returning ones in every month of 2025, yet repeat orders from the one customer in four who came back make 53% of the year's revenue.
The data
Fern & Fig online plant shop, orders in 2025
A small online plant shop that grew its ad spend through 2025. Most buyers order one starter plant and vanish; about one in four comes back for pots, soil and bigger plants.
order_id | order_date | customer_id | revenue |
|---|---|---|---|
| FF-50003 | 2025-01-01 | C-1046 | 39.78 |
| FF-50004 | 2025-01-01 | C-1047 | 44.17 |
| FF-50006 | 2025-01-02 | C-1028 | 42.99 |
| FF-50008 | 2025-01-02 | C-1063 | 27.29 |
Step 1
Find each customer's first order
One date per customer, computed over their whole history. Counting customers by the month of that date gives new customers per month: the shop's ads bring a few more every month.
Tableau
{ FIXED [customer_id] : MIN([order_date]) }SQL
WITH firsts AS (
SELECT customer_id, MIN(order_date) AS first_order
FROM input
GROUP BY customer_id
)
SELECT
date_trunc('month', first_order) AS month,
COUNT(*) AS new_customers
FROM firsts
GROUP BY 1
ORDER BY 1Rows
| Month | New customers |
|---|---|
| Jan 2025 | 68 |
| Feb 2025 | 80 |
| Mar 2025 | 83 |
| Apr 2025 | 84 |
| May 2025 | 91 |
| Jun 2025 | 88 |
| Jul 2025 | 93 |
| Aug 2025 | 103 |
| Sep 2025 | 109 |
| Oct 2025 | 119 |
| Nov 2025 | 115 |
| Dec 2025 | 125 |
Step 2
Tag every month's customers new or returning
[First order] is the FIXED field from step 1. Put customer_type on Color and COUNTD([customer_id]) on Rows. Each customer is counted once per month, so the two parts add up to that month's customers. New customers are the bigger part in every month.
Tableau
IF DATETRUNC('month', [order_date]) = DATETRUNC('month', [First order]) THEN "New"
ELSE "Returning"
ENDSQL
WITH t AS (
SELECT
*,
date_trunc('month', order_date) AS month,
date_trunc('month', MIN(order_date) OVER (PARTITION BY customer_id)) AS first_month
FROM input
)
SELECT
month,
CASE
WHEN month = first_month THEN 'New'
ELSE 'Returning'
END AS customer_type,
COUNT(DISTINCT customer_id) AS customers
FROM t
GROUP BY 1, 2
ORDER BY 1, 2Rows
| Month | Customer type | Customers |
|---|---|---|
| Jan 2025 | New | 68 |
| Feb 2025 | New | 80 |
| Feb 2025 | Returning | 6 |
| Mar 2025 | New | 83 |
| Mar 2025 | Returning | 17 |
| Apr 2025 | New | 84 |
| Apr 2025 | Returning | 20 |
| May 2025 | New | 91 |
| May 2025 | Returning | 52 |
| Jun 2025 | New | 88 |
| Jun 2025 | Returning | 42 |
| Jul 2025 | New | 93 |
| Jul 2025 | Returning | 64 |
| Aug 2025 | New | 103 |
| Aug 2025 | Returning | 82 |
| Sep 2025 | New | 109 |
| Sep 2025 | Returning | 82 |
| Oct 2025 | New | 119 |
| Oct 2025 | Returning | 97 |
| Nov 2025 | New | 115 |
| Nov 2025 | Returning | 105 |
| Dec 2025 | New | 125 |
| Dec 2025 | Returning | 115 |
New customers win every month. Do they win the revenue?
No. Count heads and new customers are the bigger group in all twelve months: in December, 125 new against 115 returning. Count money and the picture flips. The 296 customers who came back, one in four, made 53% of the year's revenue through their repeat orders, and 65% of December's.
Step 3
Now split the revenue the same way
Same split, different measure, opposite picture. A first order is one small starter plant; a returning customer buys pots, soil and bigger plants. From July on, the smaller group brings in more money every month.
Tableau
SUM([revenue])
// Color: the New / Returning field from step 2SQL
WITH t AS (
SELECT
*,
date_trunc('month', order_date) AS month,
date_trunc('month', MIN(order_date) OVER (PARTITION BY customer_id)) AS first_month
FROM input
)
SELECT
month,
CASE
WHEN month = first_month THEN 'New'
ELSE 'Returning'
END AS customer_type,
ROUND(SUM(revenue), 2) AS revenue
FROM t
GROUP BY 1, 2
ORDER BY 1, 2Rows
| Month | Customer type | Revenue |
|---|---|---|
| Jan 2025 | New | $2,172 |
| Feb 2025 | New | $2,545 |
| Feb 2025 | Returning | $372 |
| Mar 2025 | New | $2,644 |
| Mar 2025 | Returning | $1,046 |
| Apr 2025 | New | $2,607 |
| Apr 2025 | Returning | $1,160 |
| May 2025 | New | $2,991 |
| May 2025 | Returning | $3,110 |
| Jun 2025 | New | $3,054 |
| Jun 2025 | Returning | $2,455 |
| Jul 2025 | New | $2,963 |
| Jul 2025 | Returning | $3,909 |
| Aug 2025 | New | $3,263 |
| Aug 2025 | Returning | $4,548 |
| Sep 2025 | New | $3,601 |
| Sep 2025 | Returning | $5,133 |
| Oct 2025 | New | $3,732 |
| Oct 2025 | Returning | $6,203 |
| Nov 2025 | New | $3,725 |
| Nov 2025 | Returning | $6,432 |
| Dec 2025 | New | $3,972 |
| Dec 2025 | Returning | $7,368 |
A dashboard that only shows customer counts tells this shop to keep buying ads. The revenue split says the real engine is the second order, and that the ads are worth what they lead to, not what the first basket pays.
How do I filter dates without making old customers look new?
Find the first order over all of a customer's history, then filter. Move the slider to choose the first month shown.
Step 5
Filter the months without breaking the split
The first-order date is found over the whole year, then the months are filtered. Tableau's FIXED does this for you because it runs before dimension filters; in SQL, the window sits in the CTE and the WHERE comes after it.
Tableau
{ FIXED [customer_id] : MIN([order_date]) }
// Filters: MONTH([order_date]) >= {knob.from_month}, not added to contextSQL
WITH t AS (
SELECT
*,
date_trunc('month', order_date) AS month,
date_trunc('month', MIN(order_date) OVER (PARTITION BY customer_id)) AS first_month
FROM input
)
SELECT
month,
CASE
WHEN month = first_month THEN 'New'
ELSE 'Returning'
END AS customer_type,
COUNT(DISTINCT customer_id) AS customers
FROM t
WHERE month(order_date) >= 7
GROUP BY 1, 2
ORDER BY 1, 2Rows
| Month | Customer type | Customers |
|---|---|---|
| Jul 2025 | New | 93 |
| Jul 2025 | Returning | 64 |
| Aug 2025 | New | 103 |
| Aug 2025 | Returning | 82 |
| Sep 2025 | New | 109 |
| Sep 2025 | Returning | 82 |
| Oct 2025 | New | 119 |
| Oct 2025 | Returning | 97 |
| Nov 2025 | New | 115 |
| Nov 2025 | Returning | 105 |
| Dec 2025 | New | 125 |
| Dec 2025 | Returning | 115 |