Home > front end >  Why can't I sum values ​for a given period with intervals present in another table?
Why can't I sum values ​for a given period with intervals present in another table?

Time:10-06

I'm using a software. I can not change the model.

The software is a film rental manager.

In the database, I have some clients and differents type of rental and different type of client (free, vip, vip , ...)

A client can rent a movie for one day, one week, buy a movie, etc. He starts as a free client and if he pay, he can get VIP or VIP offer.

Inside this table (Rent), I have the information about a rent. I know which type of rent it is (10 is for rent only for one day), the date and the duration of the movie rental.

owner_id Type Date hours
POA 10 2021-01-28 8
POA 10 2021-06-29 7.30

POA is the owner_id. It's a natural id. It comes from my client table :

id c_id Name
123 POA Paul

And I have a table that contains all the offer's history for one client.

user_cid group from to
poa free 2000-01-01 2021-04-30
poa VIP 2021-05-01 2021-06-30
poa VIP 2021-07-01 2099-12-31

2000-01-01 and 2099-12-31 are default value given by the software. I can't change them.

2000-01-01 is the default value when a user is created and 2099-12-31 means that this offer is the current client's offer.

In this case, Paul was a free member from the day he created his account to the 2021-04-30 and then he became a VIP member from the 2021-05-01 to the 2021-06-30. After this, he subscribed to a VIP offer from the 2021-07-01 and it's still his current offer to this day.

Now what I'm trying to do, is to display a history of films rented by Paul in a given period. But I would like to separate the history by group.

Per example If I give a period from 2021-01-01 to 2021-06-30, a desired input would be this :

Name Group Rent (1 day)
Paul free 8
Paul VIP 7.30

I can see the total duration of the type 10 rentals (which is one-day rental) for each group. When Paul was a free user he rented films for 8 hours and when he was a VIP user he rented for 7.30 hours (as we can see in the first and the third table).

So I tried this :

SELECT p.name, h.group, sum(caase when r.type = '10' then r.hours else 0 end) 

FROM client p 
left outer join history h
 on h.user_cid = p.c_id
join rent r 
 on r.owner_id = p.c_id
and r.date between '2021-01-01' and '2021-06-30'

where p.c_id = 'poa'

group by p.name

With this request I have this result (it sums all the hours and not by group) :

Name Group Rent (1 day)
Paul free 15.30
Paul VIP 15.30

So I don't know how to handle the history date.

I have to handle it like this :

If the start period is 2021-01-01 and the end period is 2021-06-30 then sum the duration from the start period to the end of the free offer 2021-04-30 and then in an other row sum the duration from the start of the vip offer 2021-05-01 to the end period. (And repeat this pattern if the member changed his subscription more than 2 time).

Finally, I have to handle the default date 2000-01-01 and 2099-12-31 too. I thought about doing something like this :

caase when from '2000-01-01' then `2021-01-01` else r.date end

PS :

Why can't I post my question when I write 'case' inside a code block ? I had to write it with two 'a' to post it.

UPDATE

Result of ekochergin's soluion :

Name Group Rent (1 day)
Paul free 7.30
Paul VIP 0

It didn't sum correctly. 7.30 is supposed to be in the VIP group and VIP is 0 (the result should be 7.30').

CodePudding user response:

as I understood the question, all you need is to show for how many hours a user rented something divided by user's statuses (free, VIP, VIP )

If so, you're almost there. I believe the problem is in "r.date between" condition.

when I changed it to

and r.date between h.date_from and h.date_to

the query gave me answer which seems to be correct.

PS. Not sure if you need to use left join here. As far as I can understand the logic, I think a regular join suits better

UPD: would this help?

SELECT p.name, 
       h.group_name, 
       sum(case when r.type = '10' then r.hours else 0 end) 
  FROM client p 
  left join history h
    on h.user_cid = p.c_id
  join rent r 
    on r.owner_id = p.c_id
   and r.date between h.date_from and h.date_to
 where p.c_id = 'poa'
   and r.date between '2021-01-01' and '2021-06-30'
 group by p.name, h.group_name

UPD2: Are you sure you have tested on same data as in the question? On my test system it gave exactly result you needed

result

UPD3: here, check the result with some additional test data Note for simplicity reason I have commented date limitation clause

result with additional data

CodePudding user response:

It looks like you just need an interval check on the history table, then simply add the group to the group by clause

SELECT
  p.name,
  h.[group],
  [Rent (1 day)] = SUM(CASE WHEN r.type = '10' THEN r.hours END) 
FROM client c 
JOIN history h ON h.user_cid = c.c_id
LEFT JOIN rent r ON r.owner_id = c.c_id
  AND r.date >= h.[from] AND r.date <= h.to
WHERE c.c_id = 'poa'
GROUP BY
  c.name,
  h.[group];

Notes:

  • Better not to use reserver keywords such as from or group as object or column names
  • A history table should ideally not even have an end time, just calculate the end time by referring to the next row.
  • If the dates have time componenets then you need a half-open interval r.date >= h.[from] AND r.date < h.to
  • Related