I have two tables:
BusinessViews:
| id | createdAt | businessId | userId |
|---|---|---|---|
| 1 | 2022-01-19 18:00:00 | 1 | 1 |
| 2 | 2022-01-19 18:02:00 | 1 | 1 |
| 3 | 2022-01-19 18:05:00 | 1 | 1 |
| 4 | 2022-01-19 18:05:50 | 1 | 1 |
| 5 | 2022-01-19 18:07:00 | 1 | 1 |
| 6 | 2022-01-19 18:08:00 | 1 | 1 |
| 7 | 2022-01-19 18:10:00 | 1 | 1 |
BusinessClients:
| id | status | createdAt | userId | createdBy | businessId |
|---|---|---|---|---|---|
| 1 | 1 | 2022-01-19 18:01:00 | 1 | 1 | 1 |
| 2 | 2 | 2022-01-19 18:03:00 | 1 | 2 | 1 |
| 3 | 0 | 2022-01-19 18:06:00 | 1 | 1 | 1 |
| 4 | 1 | 2022-01-19 18:07:30 | 1 | 1 | 1 |
| 5 | 0 | 2022-01-19 18:09:00 | 1 | 2 | 1 |
The BusinessViews is for register the business page views by users and BusinessClients for the clients history. To get the count of total page views for businessId = 1 for example I simply did this:
SELECT COUNT(*) FROM BusinessViews WHERE businessId = 1 GROUP BY businessId Result: 7
But now I want to segment this result to get the count of views made by clients and the count of views made by non-clients users at the moment of view. For that, let me explain the dynamics of BusinessClients: with this table users can request to be clients of any business and the business employees can refuse/accept (in case of request) and remove (in case of the user is already a client). If the user has no records in the table it’s because he was never a client of the business and if the user has records in the table they can have three types of status:
status = 1means user sent the request to business (If the user does not have records yet, this is the only possibility)status = 2means user request was accepted by a business employeestatus = 0ifuserId = createdBymeans user leaved the business and ifuserId != createdBymeans employee refused the request (if previous status = 1) or removed user of the business (if previous status = 2)
Taking that into account, the result I would like to get is:
Client views: 2 Non-client views: 5
I know I have to work with BusinessClients.status and BusinessClients.createdAt ranges according to BusinessViews.createdAt value. But I’m completely out of ideas on how to do this query. I don’t know if I should use left join or subqueries and I can’t think of any way to get these results.
What is the correct way to do this?
UPDATE:
Explaining the desired result: I have 7 views and I want to know how many of these views came from clients and non-clients users at the moment of the view (I’m using only one userId to simplify understanding but there may be multiple users registering views in BusinessViews table and joining and leaving BusinessClients table), so:
- BusinessView with
id = 1was created at 2022-01-19 18:00:00 and at this moment the corresponding user is not a client yet (because he was never a client), so:
Client Views: 0andNon-client views: 1.
- BusinessView with
id = 2was created at 2022-01-19 18:02:00 and at this moment the corresponding user is not a client yet again (because thecurrent status still = 1at this time and only changed at 2022-01-19 18:03:00 (BusinessClient withid = 2), so:
Client Views: 0andNon-client views: 2.
- BusinessView with
id = 3was created at 2022-01-19 18:05:00 and at this moment the corresponding user is already a client (becausestatus = 2was created at 2022-01-19 18:03:00 (BusinessClient withid = 2) and only changed at 2022-01-19 18:06:00 (BusinessClient withid = 3), so:
Client Views: 1andNon-client views: 2.
- BusinessView with
id = 4same as previous item, so:
Client Views: 2andNon-client views: 2.
- BusinessView with
id = 5was created at 2022-01-19 18:07:00 and at this moment the corresponding user is not a client anymore (becausestatus = 0was created at 2022-01-19 18:06:00 (BusinessClient withid = 3) and only changed at 2022-01-19 18:07:30 (BusinessClient withid = 4), so:
Client Views: 2andNon-client views: 3
- BusinessView with
id = 6was created at 2022-01-19 18:08:00 and at this moment the corresponding user still not a client (becausestatus = 1was created at 2022-01-19 18:07:30 (BusinessClient withid = 4) and only changed at 2022-01-19 18:09:00 (BusinessClient withid = 5), so:
Client Views: 2andNon-client views: 4.
- BusinessView with
id = 7same as previous item (the only difference is that this is the last record so far), so
Client Views: 2andNon-client views: 5.
The question is: where is the BusinessViews.createdAt between the BusinessClients.createdAt records and what is the corresponding BusinessClients.status for the user at BusinessViews.createdAt?
Advertisement
Answer
UPDATED
Thank you for adding the explanation of the join.
Client views: 2 Non-client views: 5
WITH BusinessViews (id, createdAt, businessId, userId) AS (
SELECT 1, '2022-01-19 18:00:00', 1, 1 UNION ALL
SELECT 2, '2022-01-19 18:02:00', 1, 1 UNION ALL
SELECT 3, '2022-01-19 18:05:00', 1, 1 UNION ALL
SELECT 4, '2022-01-19 18:05:50', 1, 1 UNION ALL
SELECT 5, '2022-01-19 18:07:00', 1, 1 UNION ALL
SELECT 6, '2022-01-19 18:08:00', 1, 1 UNION ALL
SELECT 7, '2022-01-19 18:10:00', 1, 1
), BusinessClients (id, status, createdAt, userId, createdBy, businessId) AS (
SELECT 1, 1, '2022-01-19 18:01:00', 1, 1, 1 UNION ALL
SELECT 2, 2, '2022-01-19 18:03:00', 1, 2, 1 UNION ALL
SELECT 3, 0, '2022-01-19 18:06:00', 1, 1, 1 UNION ALL
SELECT 4, 1, '2022-01-19 18:07:30', 1, 1, 1 UNION ALL
SELECT 5, 0, '2022-01-19 18:09:00', 1, 2, 1
)
SELECT
COUNT(CASE WHEN bcs.status IS NULL OR bcs.status <> 2 THEN 1 END) 'non-client-views',
COUNT(CASE WHEN bcs.status = 2 THEN 1 END) 'client-views'
FROM BusinessViews bv
LEFT JOIN LATERAL (
SELECT status
FROM BusinessClients bc
WHERE bc.businessID = bv.businessID
AND bc.userId = bv.userId
AND bc.createdAt < bv.createdAt
ORDER BY bc.id DESC
LIMIT 1
) bcs ON true
WHERE bv.businessId = 1;
I have included the CTEs to save others the effort, if they fancy trying this.