I have two columns coming from my sql query- month, value i.e. values are coming monthwise. My requirement is to club these months in the group of 3 months wise...and the values should come the average of these 3.
Ex.I have following data-
Month Values
Mar-14 50
Apr-14 51
May-14 52
Jun-14 53
Jul-14 54
Aug-14 55
Sep-14 56
Oct-14 57
Nov-14 58
Dec-14 59
Jan-15 60
Feb-15 61
Mar-15 62
Apr-15 63
May-15 64
Jun-15 65
Jul-15 66
Aug-15 67
Sep-15 68
Oct-15 69
Nov-15 70
Dec-15 71
Jan-16 72
Feb-16 73
Mar-16 74
Apr-16 75
May-16 76
Jun-16 77
Jul-16 78
Aug-16 79
Sep-16 80
Oct-16 81
Nov-16 82
Dec-16 83
Jan-17 84
Feb-17 85
Mar-17 86
How can I achieve following output in MySql-
3 Months Clubing Avg of Values
Mar-14 51
Jun-14 54
Sep-14 57
Dec-14 60
Mar-15 63
Jun-15 66
Sep-15 69
Dec-15 72
Mar-16 75
Jun-16 78
Sep-16 81
Thanks in Advance
A bit messy but you could use variables -assuming you have an incrementing id column (or soemthing you can order by)
drop table if exists t;
create table t(id int auto_increment primary key,Month varchar(10), Valus int);
insert into t (month,valus) values
('Mar-14', 50),
('Apr-14', 51),
('May-14', 52),
('Jun-14', 53),
('Jul-14', 54),
('Aug-14', 55),
('Sep-14', 56),
('Oct-14', 57),
('Nov-14', 58),
('Dec-14', 59);
select id,mth,rt
from
(
select id,month,valus,
#count:=#count+1 counter,
if(#count=1,#mth:=month,#mth:=#mth) mth,
if(#count=1,#block:=#block+1,#block:=#block) block,
if(#count<3,#sum:=#sum+valus,#sum:=(#sum+valus) / 3) rt,
if(#count=3,#count:=0,#count:=#count) creset,
if(#count=0,#sum:=0,#sum:=#sum) sumreset
from t
cross join (select #m ='',#count:=0,#sum:=0,#block:=0,#mth:='') s
order by id
)t
where counter = 3;
+----+--------+------+
| id | mth | rt |
+----+--------+------+
| 3 | Mar-14 | 51 |
| 6 | Jun-14 | 54 |
| 9 | Sep-14 | 57 |
+----+--------+------+
3 rows in set (0.03 sec)
Slightly less messy but using sql's avg function and using variables to fill down the first month in a 3 month block
select block,mth,avg(valus)
from
(
select id,month,valus,
#count:=#count+1 counter,
if(#count=1,#mth:=month,#mth:=#mth) mth,
if(#count=1,#block:=#block+1,#block:=#block) block,
if(#count=3,#count:=0,#count:=#count) creset
from t
cross join (select #block:=0,#count:=0,#mth:='') s
order by id
) t
group by block,mth
order by block,mth
+-------+--------+------------+
| block | mth | avg(valus) |
+-------+--------+------------+
| 1 | Mar-14 | 51.0000 |
| 2 | Jun-14 | 54.0000 |
| 3 | Sep-14 | 57.0000 |
| 4 | Dec-14 | 59.0000 |
+-------+--------+------------+
4 rows in set (0.05 sec)
Try this
create temporary table tab (month1 varchar(30), id int);
insert into tab (month1,id)
values('Mar-14' ,50),
('Apr-14' ,51),
('May-14' ,52),
('Jun-14' ,53),
('Jul-14' ,54),
('Aug-14' ,55),
('Sep-14' ,56),
('Oct-14' ,57),
('Nov-14' ,58),
('Dec-14' ,59),
('Jan-15' ,60),
('Feb-15' ,61),
('Mar-14' ,62);
set #row_number = 0;
select *
from tab where (#row_number := #row_number+1)%3= 1;
Result
month1 id
'Mar-14' '50'
'Jun-14' '53'
'Sep-14' '56'
'Dec-14' '59'
'Mar-14' '62'
Suppose I have a table with columns name and age with following data:
name | age
------|-----
harry | 12
adam | 13
eve | 14
jill | 14
John | 16
alice | 19
smith | 33
bill | 43
bob | 66
jones | 78
I want to first arrange the rows in increasing order of age (already done above)
Then I want to supply a "group size", say 3. So mentally divide the table in blocks of 3 rows starting from top
name | age
------|-----
harry | 12
adam | 13
eve | 14
------------
jill | 14
John | 16
alice | 19
------------
smith | 33
bill | 43
bob | 66
------------
jones | 78
Last block can be less than 3 if num rows is not a multiple of 3.
I need the top and bottom values of the age column in each block. So the output should be:
min age|max age
-------|-------
12 | 14
14 | 19
33 | 66
78 | 78
The naive way using nested tables is not efficient:
select
min(T.age),
max(T.age)
from
(select
age
from
users
order by age limit 3 offset 6
) as T
I prefer to avoid selecting rows and work only with aggregates.
Database: MySQL and H2.
E.g.:
SELECT MIN(age)
, MAX(age)
FROM
( SELECT x.*
, FLOOR(#i:=#i+1/3)*3 i
FROM my_table x
, (SELECT #i:=0) vars ORDER BY age,name) n
GROUP
BY i;
I have data like in table.
Item | 7/7/15 | 7/8/15 | 7/9/15
1 | 23 | 24 | 25
2 | 26 | 74 | 96
and
I have table which has,
Item | Date | Number
1 | 7/9/15 | 56
1 | 7/7/15 | 75
1 | 7/8/15 | 63
I want to find sum of Number from 7/7/15 to 7/8/15 from table 1 and sum of the number from second table.
My table should look like
Item | StartDate | EndDate | no. | TotalNumber
item 7/7/15 7/8/15 7/9/15
1 23 24 25
2 26 74 96
item date number
1 7/9/15 56
1 7/7/15 75
1 7/8/15 63
.
SELECT
i1.Item,
'7/7/15' AS "StartDate",
'7/8/15' AS "EndDate",
(SELECT SUM(`7/7/15`)+SUM(`7/8/15`) FROM table1 WHERE item=i1.item) AS no,
(SELECT SUM(number) FROM table2 WHERE item=i1.item) "TotalNumber"
FROM
table2 i2
RIGHT OUTER JOIN table1 i1 on i1.item=i2.item;
item startdate enddate no TotalNumber
1 7/7/15 7/8/15 47 194
1 7/7/15 7/8/15 47 194
1 7/7/15 7/8/15 47 194
2 7/7/15 7/8/15 100
.
It's working..
In a re-print of a deleted question an hour ago,
if I wanted to print out the numbers 1-100, with 10 numbers to a line
in the mysql shell, how would I go about doing that?
Community wiki answer so as not to collect points. Edit at will.
select theAnswer
from
( select #rn:=#rn+1 as rownum,
concat(1+(#rn-1)*10,' ',2+(#rn-1)*10,' ',3+(#rn-1)*10,' ',4+(#rn-1)*10,' ',5+(#rn-1)*10,' ',
6+(#rn-1)*10,' ',7+(#rn-1)*10,' ',8+(#rn-1)*10,' ',9+(#rn-1)*10,' ',10+(#rn-1)*10,' ') as theAnswer
from (select #rn:=0) params1
cross join (select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10) params2
) xDerived;
+---------------------------------+
| theAnswer |
+---------------------------------+
| 1 2 3 4 5 6 7 8 9 10 |
| 11 12 13 14 15 16 17 18 19 20 |
| 21 22 23 24 25 26 27 28 29 30 |
| 31 32 33 34 35 36 37 38 39 40 |
| 41 42 43 44 45 46 47 48 49 50 |
| 51 52 53 54 55 56 57 58 59 60 |
| 61 62 63 64 65 66 67 68 69 70 |
| 71 72 73 74 75 76 77 78 79 80 |
| 81 82 83 84 85 86 87 88 89 90 |
| 91 92 93 94 95 96 97 98 99 100 |
+---------------------------------+
The stuff inside of the from ( ) is a derived table, and every derived table needs an alias, which is xDerived.
#rn is a row number variable. It gets initialized in the params1 derived table. One row.
params2 is another derived table, with rows 1 to 10 as values.
The cross join creates a cartesian product (all permutations) of a 1x10 which results in 10 rows, with #rn getting incremented with each row.
As we only want one column of output, the outer wrapper does the final select for just one column to avoid outputting the row number column.
If one wanted to use a WHILE DO loop in mysql, one could use a stored procedure.
Generally what i do is create a table (normally a temp table) and populate that with a stored procedure.
CREATE TABLE `numTable` (
`Id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`Id`)
)//
CREATE PROCEDURE dowhile(IN tableLimit INT)
BEGIN
DECLARE pointer INT DEFAULT tableLimit;
WHILE pointer > 0 DO
INSERT numTable VALUES (NULL);
SET pointer = pointer - 1;
END WHILE;
END//
CALL dowhile(100)//
now you may need to use DELIMITER but for the sake of consistency i have just copied what worked in SQL Fiddle by setting the Schema Delimiter to be // (forth button bellow the Schema Window)
then from there i then do a select of this table by giving each row a group id. since you want groups of 10 i have set the group to be multiples of 10 and then group by this group id using GROUP_CONCAT to make the rows.
select myRow
from (
SELECT group_concat(id SEPARATOR ', ') as `myRow`, CEIL(id/10) as `groupId`
FROM numTable group by `groupID`) as myTable;
SQL Fiddle
since we don't want to show the group id i then make this a sub-select and only select my new rows. if you use this in something like PHP or C# to output the rows you can just do the one select since you don't have to output everything you get from a query result.
In MariaDB with the sequence plugin:
select group_concat(seq order by seq separator ' ')
from seq_1_to_100
group by (seq-1) div 10;
| group_concat(seq order by seq separator ' ') |
|----------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 |
| 11 12 13 14 15 16 17 18 19 20 |
| 21 22 23 24 25 26 27 28 29 30 |
| 31 32 33 34 35 36 37 38 39 40 |
| 41 42 43 44 45 46 47 48 49 50 |
| 51 52 53 54 55 56 57 58 59 60 |
| 61 62 63 64 65 66 67 68 69 70 |
| 71 72 73 74 75 76 77 78 79 80 |
| 81 82 83 84 85 86 87 88 89 90 |
| 91 92 93 94 95 96 97 98 99 100 |
A generic solution:
set #num_cols := 10;
set #max := 100;
select group_concat(seq order by seq separator ' ')
from seq_1_to_1000000
where seq <= #max
group by (seq-1) div #num_cols
order by min(seq);
If you want them all in one cell:
select group_concat(col separator '\n')
from (
select group_concat(seq order by seq separator '\t') as col
from seq_1_to_1000000
where seq <= #max
group by (seq-1) div #num_cols
) drv
Want to have columns?
set #num_cols := 7;
set #num_rows := 3;
set #sql := (
concat('select ', (
select group_concat('(seq-1)*', #num_cols, '+', seq, ' as c', seq)
from seq_1_to_1000000
where seq <= #num_cols
),' from seq_1_to_1000000 where seq<=', #num_rows)
);
prepare stmt from #sql;
execute stmt;
| c1 | c2 | c3 | c4 | c5 | c6 | c7 |
|----|----|----|----|----|----|----|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
If you don't have MariaDB with the sequence plugin, you can create a helper table with sequence numbers. Ask Drew how to do that :-)
To clarify my Title
I would like to tabulate how far behind the leader, each successive finisher is from 1st place as shown in my table below.
Finish | Points | Points Behind
1 | 102 |
2 | 92 | 10
3 | 82 | 20
4 | 71 | 31
5 | 61 | 41
6 | 50 | 52
7 | 40 | 62
8 | 30 | 72
9 | 20 | 82
10 | 10 | 92
Select
snpc_stats.gamedetail.Finish,
snpc_stats.gamedetail.Points,
some code I don't know As 'Points Behind'
From
snpc_stats.gamedetail
Where
snpc_stats.gamedetail.GamesID = 113
You can get the points from first finish and do a cross join with rest of the table.
SQL Fiddle
select gd.Finish, gd.Points,
t.Points-gd.Points as PointsBehind
from gamedetail gd
cross join ( select max(Points) from gamedetail where Finish =1) t