SQL Server 2008 : CASE WHEN auto increments/groups data - sql-server-2008

I have a table that stores data like the below :
MonthOpened | MONTH | Collected
--------------------------------
01/05/2012 | 1 | £10.00
01/05/2012 | 2 | £30.00
01/05/2012 | 3 | £30.00
01/05/2012 | 4 | £30.00
01/05/2012 | 5 | £30.00
01/05/2012 | 6 | £10.00
01/05/2012 | 7 | £30.00
01/05/2012 | 8 | £50.00
01/05/2012 | 9 | £10.00
01/05/2012 | 10 | £50.00
01/05/2012 | 11 | £100.00
01/05/2012 | 12 | £141.92
01/05/2012 | 13 | £100.00
01/05/2012 | 14 | £50.00
Month opened is the date the accounts where taken out, Month is the month that they paid (month 1 is the month the account was opened (may), month 2 would be June, month 3 would be july and so on. At the moment this goes all the way through to month 36.
For reference this data goes into a SSRS Matrix and appears like so
MONTH |1 |2 | 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14
----------------------------------------------------------------------------------------------------------------
01/05/2012|£10.00|£30.00|£30.00|£30.00|£30.00|£10.00|£30.00|£50.00|£10.00|£50.00|£100.00|£141.92|£100.00|£50.00
I've been asked to group these together after 12 months, so 1-12 appear, then 18, 24, 30, 36 and so on. I've done this as a quick fix by doing a generic case when
CASE
WHEN ISNULL(sp.Month, N'01') BETWEEN 01 AND 12
THEN ISNULL(sp.Month, N'01')
WHEN ISNULL(sp.Month, N'01') BETWEEN 13 AND 18
THEN 18
WHEN ISNULL(sp.Month, N'01') BETWEEN 19 AND 24
THEN 24
WHEN ISNULL(sp.Month, N'01') BETWEEN 25 AND 30
THEN 30
WHEN ISNULL(sp.Month, N'01') BETWEEN 31 AND 36
THEN 36
ELSE ''
END AS MONTH
However I need to get it so that it auto groups so that it takes in account future months (42, 48, 54, 60....) but I need to be able to do this in the SSRS query window and havent been able to find a way of getting it to work.

If you need to group by every 12th, then doing an integer division of 12 on the month subtracted by 1, will give you the interval they belong to.
You can then group by that interval.
For example:
Month 1 will be (1-1) / 12 = 0 and this will be your first interval
Month 2 will be (2-1) / 12 = 0 Still first interval
Month 13 will be (13 - 1) / 12 = 1 The beginning of second interval
Month 36 will be (36 -1) / 12 = 2 The beginning of third interval
And so forth? That way you do not have to case indefinitely.

Related

mysql getting average of client per day in a month

SELECT COUNT(client_ID) / DAY(LAST_DAY(dateRequested))
FROM `tbl_client`
WHERE dateRequested BETWEEN DATE_FORMAT(dateRequested,'%Y-%m-01') AND LAST_DAY(dateRequested)
I want to show the average of client per day in the month
client_ID | dateRequested
1 | 2018-07-04
2 | 2018-07-05
3 | 2018-07-06
4 | 2018-07-07
5 | 2018-08-04
6 | 2018-08-06
7 | 2018-08-09
i want to show
Average | Month
4 | July 2018
3 | August 2018
Try below query:
SELECT COUNT(client_ID),concat(month(dateRequested),year(dateRequested))
FROM `tbl_client`
WHERE dateRequested BETWEEN DATE_FORMAT(dateRequested,'%Y-%m-01') AND LAST_DAY(dateRequested)
group by concat(month(dateRequested),year(dateRequested))

Calculating cumulative values for every 12 months on tables with possibly null values

I have this table:
Month Year MV MI fullDate
-----------------------------------------------------------------
...
5 2015 1 5 2015-05-01
6 2015 1 10 2015-06-01
7 2015 3 10 2015-07-01
8 2015 2 10 2015-08-01
11 2015 1 10 2015-11-01
1 2016 4 10 2016-01-01
6 2016 1 20 2016-06-01
7 2016 null 10 2016-07-01
8 2016 2 5 2016-08-01
...
I need to create another table with cumulative values:
Month Year AMV AMI
-----------------------------------------------------------------
...
7 2015 3 10
8 2015 5 20
11 2015 6 30
1 2016 10 40
6 2016 11 60
7 2016 0 10
8 2016 2 15
...
The cumulative calculations must start on a July and end on June of the next year. In this example, the cumulative fields started "accumulating" from July, 2015 and ended on June, 2016. These calculations re-started on July, 2016 getting another cycle for cumulative values to "calculate"
I made a similar question before but I just found out this "periodicity" for calculations of cumulative. One more thing... some values on the first table could be null and need to be considered as 0.
Please, tell me how can this be done?
I have modified the quer from #Sebastian. The init is also in the query. the counter will reset each year and the where is not necessary
SELECT
(#amv:=IF(MONTH(fulldate)=7,MV, IF(ISNULL(MV), 0, #amv+MV))) AS AMV,
(#ami:=IF(MONTH(fulldate)=7,MI, IF(ISNULL(MI), 0, #ami+MI))) AS AMI,
fullDate
FROM
input
CROSS JOIN ( SELECT #amv := 0, #ami := 0) AS init
ORDER BY fullDate ASC;
sample
mysql> select * from input;
+----+------+------+------------+
| id | MV | MI | fullDate |
+----+------+------+------------+
| 1 | 1 | 10 | 2015-08-01 |
| 2 | 2 | 20 | 2015-09-01 |
| 3 | 3 | 30 | 2015-07-01 |
| 4 | 8 | 33 | 2016-07-01 |
| 5 | 2 | 8 | 2016-08-01 |
+----+------+------+------------+
5 rows in set (0,00 sec)
mysql> SELECT
-> (#amv:=IF(MONTH(fulldate)=7,MV, IF(ISNULL(MV), 0, #amv+MV))) AS AMV,
-> (#ami:=IF(MONTH(fulldate)=7,MI, IF(ISNULL(MI), 0, #ami+MI))) AS AMI,
-> fullDate
-> FROM
-> input
-> CROSS JOIN ( SELECT #amv := 0, #ami := 0) AS init
-> ORDER BY fullDate ASC;
+------+------+------------+
| AMV | AMI | fullDate |
+------+------+------------+
| 3 | 30 | 2015-07-01 |
| 4 | 40 | 2015-08-01 |
| 6 | 60 | 2015-09-01 |
| 8 | 33 | 2016-07-01 |
| 10 | 41 | 2016-08-01 |
+------+------+------------+
5 rows in set (0,00 sec)
mysql>
This does the trick:
SET #amv := 0, #ami := 0;
SELECT
(#amv:=IF(ISNULL(MV), 0, #amv+MV)) as AMV,
(#ami:=IF(ISNULL(MI), 0, #ami+MI)) as AMI,
fullDate
FROM
input
WHERE
fullDate >= "2015-07-01" AND
fullDate < "2016-07-01"
ORDER BY fullDate ASC;

Mysql - Rows within hourly ranges on specific days using DAYOFWEEK

I am trying to get a query that will return a result set with reading total within certain hour ranges (defined in the working_hours table) depending on the DAYOFTHEWEEK for the date with a result that looks like:
working | nonworking | weekend | date | group_id
-----------------------------------------------------------------
50.3 | 30.8 | 0 | 2015-04-01 00:00 | 7
40.3 | 60.8 | 0 | 2015-04-01 00:00 | 8
50.3 | 30.8 | 0 | 2015-04-02 00:00 | 7
40.3 | 60.8 | 0 | 2015-04-02 00:00 | 8
Working and Weekend ranges are stored in the database in working_hours, Nonworking time ranges are implied (NOT BETWEEN the other ranges on that day basically)
The tables are as following:
Readings table has the hourly readings, named readings
group_id | reading | datestamp
------------------------------------------------------
7 | 30.8 | 2015-04-01 00:00
7 | 20.2 | 2015-04-01 01:00
7 | 11.2 | 2015-04-02 00:00
7 | 20.2 | 2015-04-02 01:00
8 | 26.2 | 2015-04-01 00:00
8 | 30.2 | 2015-04-01 01:00
8 | 26.2 | 2015-04-02 00:00
8 | 30.2 | 2015-04-02 01:00
Hour Ranges are stored in the working_hours table, the day column is DAYOFTHEWEEK format (1 = Sunday, 2 = Monday, etc):
group_id | day | range_start | range_end | range_type_id | day_type_id
------------------------------------------------------------------------------
7 | 5 | 08:00:00 | 15:59:00 | 1 | 1
7 | 6 | 00:00:00 | 05:59:00 | 1 | 2
7 | 6 | 06:00:00 | 23:59:00 | 2 | 2
7 | 1 | 00:00:00 | 22:59:00 | 2 | 4
7 | 1 | 23:00:00 | 23:59:00 | 1 | 4
Day Types are in the working_hours_day_type table and where things get complicated for me, Weekday and Weekend only have one range but Start/End Weekend have two ranges ('Start Weekend' first range is working hours, second range weekend hours and 'End Weekend' first range is weekend hours, second range working hours).
id | type
------------------
1 | Weekday
2 | Start Weekend
3 | Weekend
4 | End Weekend
Range Types are in the working_hours_range_type table:
id | type
------------------
1 | Working
2 | Weekend
My Mysql knowledge is limited to simple SELECT, INSERT etc and the basics of JOINs - I have found out about HOUR(datestamp) BETWEEN 8 AND 14 but dont know how to get subqueries to iterate within a parent query using WHERE datestamp BETWEEN '2015-04-01 00:00:00' AND '2015-04-02 23:59:00' if in fact thats how its done...
I am not totally clear on what constitutes working hours or non-working hours, but does this work?
SELECT
sum(CASE WHEN rtype.range_type_id = 1 THEN reading ELSE 0 END) AS working
sum(CASE WHEN rtype.range_type_id = 2 THEN reading ELSE 0 END) AS nonworking
CASE WHEN r1.daynum in (7,1) THEN 1 ELSE 0 END as weekend
date(datestamp) as date
r1.group_id
FROM
(SELECT
group_id,
reading,
time(datestamp) as rTime,
case when weekday(datestamp) = 0 THEN 2 #weekday() monday to working hours monday
when weekday(datestamp) = 1 THEN 3
when weekday(datestamp) = 2 THEN 4
when weekday(datestamp) = 3 THEN 5
when weekday(datestamp) = 4 THEN 6
when weekday(datestamp) = 5 THEN 7
when weekday(datestamp) = 6 THEN 1
else NULL
END CASE AS daynum
FROM readings) AS r1
LEFT JOIN working_hours w1
ON (r1.daynum = w1.day)
AND (r1.group_id = w1.group_id)
AND (r1.rTime BETWEEN w1.range_start AND w1.range_end)
LEFT JOIN working_hours_day_type dtype
ON w1.day_type_id = dtype.id
LEFT JOIN working_hours_range_type rtype
ON w1.range_type_id = rtype.id
GROUP BY
CASE WHEN daynum in (7,1) THEN 1 ELSE 0 END,
date(datestamp) as date,
r1.group_id

Query to select intervals in day

I have table something like this (there's also "device_id" and "timestamp" columns)
day | interval | value
----------------------------
1 | 14 | 63 // start of a day
1 | 14 | 83
1 | 14 | 73
1 | 15 | 23
1 | 15 | 33
1 | 15 | 50
2 | 16 | 23 // start of a day
2 | 16 | 33
2 | 16 | 50
I want to select all intervals in a day. That is simple.
However, an interval can start a bit before a day flips, or end a bit past:
day | interval | value
----------------------------
7 | 14 | 63
7 | 14 | 83
8 | 14 | 73 // start of a day
8 | 15 | 23
8 | 15 | 33
8 | 15 | 50
8 | 16 | 23
8 | 16 | 33
9 | 16 | 50 // start of a day
Now I'd like to select all three intervals - or even better intervals that are mostly in that day.
SELECT ... WHERE day = 8
Gives me only parts of the start/end intervals (14, 16). That's useless, I need the complete intervals.
If there's no solution, I'll just do three queries, but there might be some SQL trick I'm not aware of?
It's MySQL, called from PHP.
More visually:
day 7 | day 8 | day 9
------------------+-------------------+---------------
###13### ###14### ###15### ###16### ###17###
... 63 83 73 23 33 50 23 33 50 ...
I want all values in day 8 -> intervals 14, 15, 16
I think you are looking for this:
SELECT * FROM intervals
WHERE interval IN (
SELECT DISTINCT interval FROM intervals WHERE day = 8)
This selects all interval data where at least one of the entries for that interval occurs in day 8. The subquery determines which unique intervals happen in the day, which is then used by the outer query to select their specifics.
SELECT DISTINCT y.*
FROM my_table x
JOIN my_table y
ON y.some_column = x.some_column
WHERE x.some_other_column = 8;

mysql Return amount of order for hour with on colum day of month

I have a mysql db which I use to return amounts of orders by hour in a specific day. I use this SELECT statement for that.
select
hour(datains),sum(valore)
from
ordini
where (stato=10 or stato = 1 ) and DATE(datains) = DATE_SUB(CONCAT(CURDATE(), ' 00:00:00'), INTERVAL 0 DAY)
group by hour(datains)
order by
id DESC
It returns:
+--------------+---------------+
| hour datains | valore |
| 12 | 34 |
| 11 | 56 |
| 10 | 134 |
+-------------------------------
Now I need to have columns for a certain number of days, like this.
+--------------+---------------+--------------+--------------+
| hour datains | 01-01-2014 | 02-01-2014 | 03-01-2014 |
| 12 | 34 | 34 | 77 |
| 11 | 56 | 0 | 128 |
| 10 | 134 | 66 | 12 |
+------------------------------+-----------------------------+
Is this possible?
It seems you have a table ordini with columns datains, valore, and stato.
Perhaps you can try this query to generate hour-by-hour aggregates for a three days' worth of recent sales, but not including today.
SELECT DATE_FORMAT(datains, '%Y-%m-%d %H:00') AS hour,
SUM(valore) AS valore
FROM ordini
WHERE (stato = 1 OR stato = 10)
AND datains >= CURRENT_DATE() - INTERVAL 3 DAY
AND datains < CURRENT_DATE
GROUP BY DATE_FORMAT(datains, '%Y-%m-%d %H:00')
ORDER BY DATE_FORMAT(datains, '%Y-%m-%d %H:00')
This will give you a result set with one row for each hour of the three days, for example:
2014-01-01 10:00 456
2014-01-01 11:00 123
2014-01-02 10:00 28
2014-01-02 11:00 350
2014-01-02 12:00 100
2014-01-02 13:00 17
2014-01-03 10:00 321
2014-01-03 11:00 432
2014-01-03 12:00 88
2014-01-03 13:00 12
That's the data summary you have requested, but formatted row-by-row. Your next step is to figure out an appropriate technique to pivot that result set, formatting it so some rows become columns.
It happens that I have just written a post on this very topic. It is here:
http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/