PHIL Sawyer
asked on
Increments
Hello
I have a data set where it contains customers and no of days columns
eg
Customer Days
A 5
B 55
C 765
D 123 ETC ETC
....
I want to be able to group the days in 30 day increments (0 to 30 then 61 to 90 .. all the way to 1000) - this could be a very long Case statement. Is there another succinct way?
Customer Days Grouping
A 5 0 to 30 ETC ETC
Regards
I have a data set where it contains customers and no of days columns
eg
Customer Days
A 5
B 55
C 765
D 123 ETC ETC
....
I want to be able to group the days in 30 day increments (0 to 30 then 61 to 90 .. all the way to 1000) - this could be a very long Case statement. Is there another succinct way?
Customer Days Grouping
A 5 0 to 30 ETC ETC
Regards
no need for additional data to join to, just use simple division to identify the buckets
SELECT customer, days, 30 * FLOOR((days-1) / 30) + 1 || ' to ' || 30 * (FLOOR((days-1) / 30) + 1) GROUPING
FROM yourdata
SELECT customer, days, 30 * FLOOR((days-1) / 30) + 1 || ' to ' || 30 * (FLOOR((days-1) / 30) + 1) GROUPING
FROM yourdata
oops, I just noticed the first range started at 0, not at 1
So that grouping is a little odd since it's not a group of 30 days, but 31
Also, what should the last grouping be? 991 to 1000?
or 991 to 1020?
Is your data constrained such that values over 1000 are impossible?
If not, what should the results be if you encounter big values 1001 or higher?
Assuming 0-30, then groups of 30 except 991-1000, then try this for the grouping portion of the query
CASE
WHEN days <= 30 THEN '0 to 30'
WHEN days >= 991 THEN '991 to 1000'
ELSE 30 * (CEIL(days / 30) - 1) + 1 || ' to ' || 30 * (CEIL(days / 30))
END
if you want groups of 30 for all sets except the first then simply remove the second WHEN
CASE
WHEN days <= 30 THEN '0 to 30'
ELSE 30 * (CEIL(days / 30) - 1) + 1 || ' to ' || 30 * (CEIL(days / 30))
END
So that grouping is a little odd since it's not a group of 30 days, but 31
Also, what should the last grouping be? 991 to 1000?
or 991 to 1020?
Is your data constrained such that values over 1000 are impossible?
If not, what should the results be if you encounter big values 1001 or higher?
Assuming 0-30, then groups of 30 except 991-1000, then try this for the grouping portion of the query
CASE
WHEN days <= 30 THEN '0 to 30'
WHEN days >= 991 THEN '991 to 1000'
ELSE 30 * (CEIL(days / 30) - 1) + 1 || ' to ' || 30 * (CEIL(days / 30))
END
if you want groups of 30 for all sets except the first then simply remove the second WHEN
CASE
WHEN days <= 30 THEN '0 to 30'
ELSE 30 * (CEIL(days / 30) - 1) + 1 || ' to ' || 30 * (CEIL(days / 30))
END
quite right: the recursive approach stops at 1020, not 1000
:) on the plus side, if I want 25 or 100 as the increment it's getting easier to adjust using the cte
(alter 30 to new number in lines 3 and 5)
:) on the plus side, if I want 25 or 100 as the increment it's getting easier to adjust using the cte
(alter 30 to new number in lines 3 and 5)
same with division. Simply change the 30 to 100 or 25.
math is cool like that. :)
math is cool like that. :)
if it was the one calculation I'd certainly agree, annoying as it is to admit that
but as you keep adding case expressions it's starting to look less inviting :)
one may also need to add a method for sorting
but as you keep adding case expressions it's starting to look less inviting :)
one may also need to add a method for sorting
SELECT
startat
, range
, count(range)
FROM (
SELECT
CASE
WHEN days <= 30 THEN '0 to 30'
ELSE 30 * (CEIL(days / 30) - 1) + 1 || ' to ' || 30 * (CEIL(days / 30))
END AS range
, 30 * (CEIL(days / 30) - 1) + 1 as startat
FROM your_table
)
GROUP BY
startat
, range
ORDER BY
startat
and (last cheap shot) if one wanted to report on all ranges (left join to data)?
Sorry, I have no idea what you're trying to say.
but that's ok, the question was answered including other variations on top condition
but that's ok, the question was answered including other variations on top condition
ASKER
I've just done a calc and the maximum number it need to go to is 1830 in terms of 30 day grouping and anything above 1830 can be categorized as the last group.
Regards
Regards
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks Guys
Great responses - I've used ststuber case statement and works a treat.
Great responses - I've used ststuber case statement and works a treat.
:) as I thought, drat
last cheap shot was meant to imply something like this:
Cheers, Paul
last cheap shot was meant to imply something like this:
WITH
range (startat, stopat) AS (
SELECT 0 AS startat, 30 AS stopat
FROM dual
UNION ALL
SELECT stopat + 1 AS startat, stopat + 30 AS stopat
FROM range
WHERE stopat + 1 < 1830
),
ranges (startat, stopat, range) AS (
SELECT startat, stopat, startat || ' - ' || stopat AS range FROM range
UNION ALL
SELECT 1831, NULL, '1831 +' FROM dual
)
SELECT
r.startat
, r.range
, count(days) AS within_range
FROM ranges r
LEFT JOIN your_table d ON (d.days BETWEEN r.startat AND r.stopat)
OR (d.days >= 1831 AND r.startat = 1831)
GROUP BY
r.startat
, r.range
ORDER BY
startat
;
IF you did ever need to report all the ranges, then a table of ranges is useful. Cheers, Paul
Open in new window