GROUP BY
кажется ненужным, но я оставлю это. Вам в основном нужна накопительная сумма.
Я бы назначил все посещения перед конкретным заказом номером заказа:
SELECT v.id AS visit_id, v.user_id,
v.started_at AS visit_date,
dense_rank() OVER (PARTITION BY v.user_id ORDER BY v.started_at) AS visit_number,
dense_rank() OVER (PARTITION BY v.user_id ORDER BY o.id) AS order_number,
o.id AS order_id,
o.created_at AS order_date,
count(o.id) over (partition by v.user_id order by v.started_at) as order_number
FROM visits v FULL JOIN
orders o
ON v.user_id = o.user_id AND
v.started_at < o.created_at AND
o.created_at < (SELECT min(visits.started_at)
FROM visits v2
WHERE v2.user_id = v.user_id AND
v2.started_at > v.started_at) AND
(v.started_at + '24:00:00'::interval) > o.created_at
GROUP BY v.id, v.user_id, v.started_at, o.id, o.created_at
ORDER BY v.started_at;
Я думаю, что это логика, которую вы хотите:
SELECT v.id AS visit_id, v.user_id,
v.started_at AS visit_date,
dense_rank() OVER (PARTITION BY v.user_id ORDER BY v.started_at) AS visit_number,
dense_rank() OVER (PARTITION BY v.user_id ORDER BY o.id) AS order_number,
o.id AS order_id,
o.created_at AS order_date,
MIN(o.order_number) OVER (PARTITION BY v.user_id ORDER BY v.started_at DESC) as order_number
FROM visits v FULL JOIN
(SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY o.user_id ORDER BY o.id) as order_number
FROM orders o
) o
ON v.user_id = o.user_id AND
v.started_at < o.created_at AND
o.created_at < (SELECT min(visits.started_at)
FROM visits v2
WHERE v2.user_id = v.user_id AND
v2.started_at > v.started_at) AND
(v.started_at + '24:00:00'::interval) > o.created_at
GROUP BY v.id, v.user_id, v.started_at, o.id, o.created_at
ORDER BY v.started_at;
Может выдать NULL
с, где вы хотите 0
с, однако.