MySQL SELECT rows as successive columns - mysql

I have this table named 'Values' in a MySQL database:
sp_id W Value_C Top_C
742 11 11.42 1.15
742 12 114.35 2.44
742 13 27.2 0.42
742 14 55.38 6.2
742 15 23.77 16.7
15 11 10.59 9.15
15 12 12.4 12.3
15 13 157.89 0.72
15 14 51.2 1.5
15 15 11.78 0.51
117 11 27.48 0.92
117 12 21.416 0.76
117 13 75.31 0.39
117 14 2.182 0.79
252 11 15.54 0.25
252 12 10.209 0.32
252 13 14.41 0.44
252 14 68.34 2.16
I am looking to rearrange the data. I am looking to get this:
sp_id 11 11 12 12 13 13 14 14 15 15
742 11.42 1.15 114.35 2.44 27.2 0.42 55.38 6.2 23.77 6.77
15 10.59 9.15 12.4 12.3 157.89 0.72 51.2 1.5 11.78 0.51
117 27.48 0.92 21.416 0.76 75.31 0.39 2.182 0.79 NULL NULL
252 15.54 0.25 10.209 0.32 14.41 0.44 68.34 2.16 NULL NULL
I can get them as columns, but I am having difficulty getting them as rows. When I use CASE, I am getting NULLs in many places.
How could I SELECT this subset with a MySQL query?
EDIT: Corrected the title.

You can try something like this if the W values are limited :
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE ValuesTable
(`sp_id` int, `W` int, `Value_C` decimal(10,2), `Top_C` decimal(10,2))
;
INSERT INTO ValuesTable
(`sp_id`, `W`, `Value_C`, `Top_C`)
VALUES
(742, 11, 11.42, 1.15),
(742, 12, 114.35, 2.44),
(742, 13, 27.2, 0.42),
(742, 14, 55.38, 6.2),
(742, 15, 23.77, 16.7),
(15, 11, 10.59, 9.15),
(15, 12, 12.4, 12.3),
(15, 13, 157.89, 0.72),
(15, 14, 51.2, 1.5),
(15, 15, 11.78, 0.51),
(117, 11, 27.48, 0.92),
(117, 12, 21.416, 0.76),
(117, 13, 75.31, 0.39),
(117, 14, 2.182, 0.79),
(252, 11, 15.54, 0.25),
(252, 12, 10.209, 0.32),
(252, 13, 14.41, 0.44),
(252, 14, 68.34, 2.16)
;
Query 1:
SELECT DISTINCT VT.sp_id,
VT11.Value_C as 11v, VT11.Top_C as 11t,
VT12.Value_C as 12v, VT12.Top_C as 12t,
VT13.Value_C as 13v, VT13.Top_C as 13t,
VT14.Value_C as 14v, VT14.Top_C as 14t,
VT15.Value_C as 15v, VT15.Top_C as 15t
FROM ValuesTable VT
LEFT OUTER JOIN ValuesTable VT11 ON VT.sp_id = VT11.sp_id AND VT11.W = 11
LEFT OUTER JOIN ValuesTable VT12 ON VT.sp_id = VT12.sp_id AND VT12.W = 12
LEFT OUTER JOIN ValuesTable VT13 ON VT.sp_id = VT13.sp_id AND VT13.W = 13
LEFT OUTER JOIN ValuesTable VT14 ON VT.sp_id = VT14.sp_id AND VT14.W = 14
LEFT OUTER JOIN ValuesTable VT15 ON VT.sp_id = VT15.sp_id AND VT15.W = 15
Results:
| SP_ID | 11V | 11T | 12V | 12T | 13V | 13T | 14V | 14T | 15V | 15T |
|-------|-------|------|--------|------|--------|------|-------|------|--------|--------|
| 742 | 11.42 | 1.15 | 114.35 | 2.44 | 27.2 | 0.42 | 55.38 | 6.2 | 23.77 | 16.7 |
| 15 | 10.59 | 9.15 | 12.4 | 12.3 | 157.89 | 0.72 | 51.2 | 1.5 | 11.78 | 0.51 |
| 117 | 27.48 | 0.92 | 21.42 | 0.76 | 75.31 | 0.39 | 2.18 | 0.79 | (null) | (null) |
| 252 | 15.54 | 0.25 | 10.21 | 0.32 | 14.41 | 0.44 | 68.34 | 2.16 | (null) | (null) |

Related

Query Group where Timediff is less than 1 minute

I am trying to figure out how to group a query result where the final Grouping should happen where the time difference is less than let's say one minute.
I have watermeter that logs my water usage and I am trying to group the results so that the graphs will make more sense. My sql queries for grouping the water usage per Year, Month, Day and hour are perfect, but then I would like to drill down to where the final result shows me a grouping where as an example I water the grass.
My Table Structure looks like:
id liter total_liters date time dater
9 3 184 2020/12/06 16:14:58 2020/12/06 16:14
10 1 185 2020/12/06 16:15:04 2020/12/06 16:15
11 3 188 2020/12/06 16:26:49 2020/12/06 16:26
12 2 190 2020/12/06 16:26:55 2020/12/06 16:26
13 2 192 2020/12/06 16:27:01 2020/12/06 16:27
14 1 193 2020/12/06 17:32:16 2020/12/06 17:32
15 1 194 2020/12/06 17:32:22 2020/12/06 17:32
16 1 195 2020/12/06 17:32:28 2020/12/06 17:32
17 1 196 2020/12/06 17:32:35 2020/12/06 17:32
18 1 197 2020/12/06 17:32:41 2020/12/06 17:32
19 1 198 2020/12/06 17:32:47 2020/12/06 17:32
20 1 199 2020/12/06 17:32:53 2020/12/06 17:32
21 1 200 2020/12/06 17:32:59 2020/12/06 17:32
22 1 201 2020/12/06 17:35:05 2020/12/06 17:35
23 1 202 2020/12/06 17:35:17 2020/12/06 17:35
24 1 203 2020/12/06 17:35:23 2020/12/06 17:35
25 1 204 2020/12/06 17:35:29 2020/12/06 17:35
26 1 205 2020/12/06 17:35:41 2020/12/06 17:35
27 1 206 2020/12/06 17:43:05 2020/12/06 17:43
28 3 209 2020/12/06 17:43:11 2020/12/06 17:43
29 2 211 2020/12/06 17:43:17 2020/12/06 17:43
30 2 213 2020/12/06 17:43:23 2020/12/06 17:43
31 2 215 2020/12/06 17:43:29 2020/12/06 17:43
32 3 218 2020/12/06 17:43:36 2020/12/06 17:43
33 2 220 2020/12/06 17:43:42 2020/12/06 17:43
And my current query looks like:
SELECT DATE_FORMAT(dater,'%H:%i') AS dater,
YEAR(dater),
MONTHNAME(dater),
DAY(dater),
HOUR(dater),
MINUTE(dater),
SUM(liter) as liter
FROM watermeter
WHERE date LIKE '2020-12-08'
GROUP BY YEAR(date), MONTHNAME(date), DAY(dater), HOUR(dater), MINUTE(dater)
ORDER BY id ASC`
The result should be to sum the Liters together by grouping them by Year then Month then Day then Hour and then it should group the results where the time difference is less than 60 seconds.
I might end up by grouping them Year, Month, Day and then by time difference is less than 60 seconds .
Like
2020-12-06 17:35:05 5 Liters
2020-12-06 17:43:05 13 Liters
Here is a phpmyaddmin sql dump if it helps
-- phpMyAdmin SQL Dump
-- version 4.6.6deb5
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: Dec 10, 2020 at 07:27 AM
-- Server version: 10.3.17-MariaDB-0+deb10u1
-- PHP Version: 7.3.11-1~deb10u1
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET #OLD_CHARACTER_SET_CLIENT=##CHARACTER_SET_CLIENT */;
/*!40101 SET #OLD_CHARACTER_SET_RESULTS=##CHARACTER_SET_RESULTS */;
/*!40101 SET #OLD_COLLATION_CONNECTION=##COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `mysensors`
--
-- --------------------------------------------------------
--
-- Table structure for table `watermeter`
--
CREATE TABLE `watermeter` (
`id` int(10) NOT NULL,
`liter` int(11) NOT NULL,
`total_liters` int(11) NOT NULL,
`date` date NOT NULL,
`time` time NOT NULL,
`dater` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `watermeter`
--
INSERT INTO `watermeter` (`id`, `liter`, `total_liters`, `date`, `time`, `dater`) VALUES
(9, 3, 184, '2020-12-06', '16:14:58', '2020-12-06 16:14:58'),
(10, 1, 185, '2020-12-06', '16:15:04', '2020-12-06 16:15:04'),
(11, 3, 188, '2020-12-06', '16:26:49', '2020-12-06 16:26:49'),
(12, 2, 190, '2020-12-06', '16:26:55', '2020-12-06 16:26:55'),
(13, 2, 192, '2020-12-06', '16:27:01', '2020-12-06 16:27:01'),
(14, 1, 193, '2020-12-06', '17:32:16', '2020-12-06 17:32:16'),
(15, 1, 194, '2020-12-06', '17:32:22', '2020-12-06 17:32:22'),
(16, 1, 195, '2020-12-06', '17:32:28', '2020-12-06 17:32:28'),
(17, 1, 196, '2020-12-06', '17:32:35', '2020-12-06 17:32:35'),
(18, 1, 197, '2020-12-06', '17:32:41', '2020-12-06 17:32:41'),
(19, 1, 198, '2020-12-06', '17:32:47', '2020-12-06 17:32:47'),
(20, 1, 199, '2020-12-06', '17:32:53', '2020-12-06 17:32:53'),
(21, 1, 200, '2020-12-06', '17:32:59', '2020-12-06 17:32:59'),
(22, 1, 201, '2020-12-06', '17:35:05', '2020-12-06 17:35:05'),
(23, 1, 202, '2020-12-06', '17:35:17', '2020-12-06 17:35:17'),
(24, 1, 203, '2020-12-06', '17:35:23', '2020-12-06 17:35:23'),
(25, 1, 204, '2020-12-06', '17:35:29', '2020-12-06 17:35:29'),
(26, 1, 205, '2020-12-06', '17:35:41', '2020-12-06 17:35:41'),
(27, 1, 206, '2020-12-06', '17:43:05', '2020-12-06 17:43:05'),
(28, 3, 209, '2020-12-06', '17:43:11', '2020-12-06 17:43:11'),
(29, 2, 211, '2020-12-06', '17:43:17', '2020-12-06 17:43:17'),
(30, 2, 213, '2020-12-06', '17:43:23', '2020-12-06 17:43:23'),
(31, 2, 215, '2020-12-06', '17:43:29', '2020-12-06 17:43:29'),
(32, 3, 218, '2020-12-06', '17:43:36', '2020-12-06 17:43:36'),
(33, 2, 220, '2020-12-06', '17:43:42', '2020-12-06 17:43:42');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `watermeter`
--
ALTER TABLE `watermeter`
ADD PRIMARY KEY (`id`),
ADD KEY `dater` (`dater`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `watermeter`
--
ALTER TABLE `watermeter`
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1061;
/*!40101 SET CHARACTER_SET_CLIENT=#OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=#OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=#OLD_COLLATION_CONNECTION */;
UPDATE 1.
Making little progress I think - Totals are not right yet.
SELECT '(a.dater, b.dater)', DATE_FORMAT(a.dater,'%H:%i') AS dater,
YEAR(a.dater),
MONTHNAME(a.dater),
DAY(a.dater),
HOUR(a.dater),
MINUTE(a.dater),
a.time,
SUM(a.liter) as liter
FROM watermeter a
INNER JOIN watermeter b
ON b.dater >= a.dater
WHERE b.dater <= DATE_ADD(a.dater, INTERVAL 60 SECOND)
AND a.date LIKE '2020-12-08' GROUP BY YEAR(a.date), MONTHNAME(a.date), DAY(a.dater), HOUR(a.dater), MINUTE(a.dater)
ORDER BY a.id ASC
Update2
So Update one does not give me the correct result. Tried now the following that I got from : MySQL GROUP BY DateTime +/- 3 seconds but also no joy yet.
SELECT COUNT(liter),DAY(dater),HOUR(dater),MINUTE(dater)
FROM watermeter
JOIN (SELECT watermeter.id, MAX(S.dater) AS ChainStartTime
FROM watermeter
JOIN (SELECT DISTINCT a.dater
FROM watermeter a
LEFT JOIN watermeter b
ON (b.dater >= a.dater - INTERVAL 60 SECOND
AND b.dater < a.dater)
WHERE b.dater IS NULL
AND a.date LIKE '2020-12-06') S
ON watermeter.dater >= S.dater
GROUP BY watermeter.id) GroupingQuery
ON watermeter.id = GroupingQuery.id
GROUP BY GroupingQuery.ChainStartTime
First find the difference in time from the previous row:
select
id,
liter,
total_liters,
dater,
lead(dater) over (order by dater) as "lead",
timediff(dater, lead(dater) over (order by dater)) as d1
from watermeter
order by dater;
output:
+----+-------+--------------+---------------------+---------------------+-----------+
| id | liter | total_liters | dater | lead | d1 |
+----+-------+--------------+---------------------+---------------------+-----------+
| 9 | 3 | 184 | 2020-12-06 16:14:58 | 2020-12-06 16:15:04 | -00:00:06 |
| 10 | 1 | 185 | 2020-12-06 16:15:04 | 2020-12-06 16:26:49 | -00:11:45 |
| 11 | 3 | 188 | 2020-12-06 16:26:49 | 2020-12-06 16:26:55 | -00:00:06 |
| 12 | 2 | 190 | 2020-12-06 16:26:55 | 2020-12-06 16:27:01 | -00:00:06 |
| 13 | 2 | 192 | 2020-12-06 16:27:01 | 2020-12-06 17:32:16 | -01:05:15 |
| 14 | 1 | 193 | 2020-12-06 17:32:16 | 2020-12-06 17:32:22 | -00:00:06 |
| 15 | 1 | 194 | 2020-12-06 17:32:22 | 2020-12-06 17:32:28 | -00:00:06 |
| 16 | 1 | 195 | 2020-12-06 17:32:28 | 2020-12-06 17:32:35 | -00:00:07 |
| 17 | 1 | 196 | 2020-12-06 17:32:35 | 2020-12-06 17:32:41 | -00:00:06 |
etc...
Then determine which times you would like to see, because they have a difference to their previous row which is larger than 60 seconds.
(The id of the column is show in x)
with cte as (
select id,
dater,
liter,
total_liters,
d1,
abs(time_to_sec(d1)) as g1,
case when abs(time_to_sec(d1))>60 then id else 0 end as x
from (
select
id,
liter,
total_liters,
dater,
lead(dater) over (order by dater) as "lead",
timediff(dater, lead(dater) over (order by dater)) as d1
from watermeter
order by dater
) tmp1
)
select * from cte;
output:
+----+---------------------+-------+--------------+-----------+------+----+
| id | dater | liter | total_liters | d1 | g1 | x |
+----+---------------------+-------+--------------+-----------+------+----+
| 9 | 2020-12-06 16:14:58 | 3 | 184 | -00:00:06 | 6 | 0 |
| 10 | 2020-12-06 16:15:04 | 1 | 185 | -00:11:45 | 705 | 10 |
| 11 | 2020-12-06 16:26:49 | 3 | 188 | -00:00:06 | 6 | 0 |
| 12 | 2020-12-06 16:26:55 | 2 | 190 | -00:00:06 | 6 | 0 |
| 13 | 2020-12-06 16:27:01 | 2 | 192 | -01:05:15 | 3915 | 13 |
| 14 | 2020-12-06 17:32:16 | 1 | 193 | -00:00:06 | 6 | 0 |
| 15 | 2020-12-06 17:32:22 | 1 | 194 | -00:00:06 | 6 | 0 |
| 16 | 2020-12-06 17:32:28 | 1 | 195 | -00:00:07 | 7 | 0 |
etc...
Next step is to determine the max(id) which 'belongs' to the x:
with cte as (
select id,
dater,
liter,
total_liters,
d1,
abs(time_to_sec(d1)) as g1,
case when abs(time_to_sec(d1))>60 then id else 0 end as x
from (
select
id,
liter,
total_liters,
dater,
lead(dater) over (order by dater) as "lead",
timediff(dater, lead(dater) over (order by dater)) as d1
from watermeter
order by dater
) tmp1
)
select
id,
dater,
liter,
total_liters
,d1,
g1,
x,
(select min(x)-1 from cte c2 where c2.id>c1.x and c2.x>0) as y
from cte c1
where c1.x<>0
;
output:
+----+---------------------+-------+--------------+-----------+------+----+------+
| id | dater | liter | total_liters | d1 | g1 | x | y |
+----+---------------------+-------+--------------+-----------+------+----+------+
| 10 | 2020-12-06 16:15:04 | 1 | 185 | -00:11:45 | 705 | 10 | 12 |
| 13 | 2020-12-06 16:27:01 | 2 | 192 | -01:05:15 | 3915 | 13 | 20 |
| 21 | 2020-12-06 17:32:59 | 1 | 200 | -00:02:06 | 126 | 21 | 25 |
| 26 | 2020-12-06 17:35:41 | 1 | 205 | -00:07:24 | 444 | 26 | NULL |
+----+---------------------+-------+--------------+-----------+------+----+------+
Note that x and y are the minimum and maximum id for your group.
Finally (this messy stuff):
with cte as (
select id,
dater,
liter,
total_liters,
d1,
abs(time_to_sec(d1)) as g1,
case when abs(time_to_sec(d1))>60 then id else 0 end as x
from (
select
id,
liter,
total_liters,
dater,
lead(dater) over (order by dater) as "lead",
timediff(dater, lead(dater) over (order by dater)) as d1
from watermeter
order by dater
) tmp1
)
select
id,
dater,
(select sum(liter) from watermeter where id between x and y) as rain
from (
select
id,
dater,
liter,
total_liters
,d1,
g1,
x,
(select min(x)-1 from cte c2 where c2.id>c1.x and c2.x>0) as y
from cte c1
where c1.x<>0
) tmp2
;
gives output:
+------+---------------------+------+
| id | dater | rain |
+------+---------------------+------+
| 10 | 2020-12-06 16:15:04 | 6 |
| 13 | 2020-12-06 16:27:01 | 9 |
| 21 | 2020-12-06 17:32:59 | 5 |
| 26 | 2020-12-06 17:35:41 | NULL |
+------+---------------------+------+
I do hope this is close to the expected output...
With the help of Luuk's code and learning a lot about "case" and "lag" and lead" and using nested selects etc. I was able to get a working query for what I wanted.
SET #wgroup := 0;
with cte as (
select
id,
dater,
liter,
total_liters,
d1,
abs(time_to_sec(d1)) as g1,
case when abs(time_to_sec(d1))>60 then #wgroup := #wgroup+1 else #wgroup end as wgroup
from (
select
id,
liter,
total_liters,
dater,
(case
WHEN lag(dater) over (order by dater) IS NULL
THEN timediff(dater, lead(dater) over (order by dater))
ELSE timediff(dater, lag(dater) over (order by dater))
END) AS d1
from watermeter where date like '2020-12-06'
order by dater
) tmp1
)
(select dater,
wgroup,
SUM(liter)
from cte
GROUP BY wgroup)
;
With this I was able to sum all values where the time difference is less than 60 second from without loosing a single line.
+---------------------+--------+------------+
| dater | wgroup | SUM(liter) |
+---------------------+--------+------------+
| 2020-12-06 16:14:58 | 0 | 4 |
| 2020-12-06 16:26:49 | 1 | 7 |
| 2020-12-06 17:32:16 | 2 | 8 |
| 2020-12-06 17:35:05 | 3 | 5 |
| 2020-12-06 17:43:05 | 4 | 308 |
| 2020-12-06 19:19:03 | 5 | 120 |
| 2020-12-06 19:31:29 | 6 | 4 |
| 2020-12-06 19:34:48 | 7 | 1 |
| 2020-12-06 20:30:08 | 8 | 1 |
| 2020-12-06 21:27:06 | 9 | 23 |
+---------------------+--------+------------+

sql how to select the next to last row of the groups with two or more rows

I have a table of performed actions over different object instances that have different versions. If I group the actions per instance and version, with this SELECT (abbreviated)
SELECT instance, version, COUNT(id) AS cnt
FROM actions
WHERE status=0
AND version IS NOT NULL
GROUP BY instance, version
I obtain this table (abbreviated)
instance | version | cnt
----------+---------+------
1021 | 18.1 | 263
1021 | 18.2 | 422
1021 | 19.1 | 949
1191 | 18.2 | 28
1195 | 18.1 | 584
1195 | 18.2 | 176
1195 | 18.3 | 437
1195 | 19.1 | 152
1195 | 19.2 | 545
1195 | 19.3 | 399
1196 | 18.3 | 844
1196 | 19.1 | 800
1197 | 18.3 | 2
1201 | 18.1 | 471
1201 | 18.2 | 584
1201 | 18.3 | 553
1201 | 19.1 | 498
1201 | 19.2 | 203
1201 | 19.3 | 36
1208 | 18.1 | 444
1208 | 18.2 | 548
1208 | 18.3 | 31
1208 | 19.2 | 357
1210 | 19.1 | 514
1211 | 18.2 | 341
1211 | 19.1 | 531
....
now, I want the row corresponding to the previous to the last version for the instances that have more than one version.
So, in the example, I need to select the rows
instance | version | cnt
----------+---------+------
1021 | 18.2 | 422
1195 | 19.2 | 545
1196 | 18.3 | 844
1201 | 19.2 | 203
1208 | 18.3 | 31
1211 | 18.2 | 341
...
I have tried GROUP BY instance HAVING count(*) >= 2 to begin by filtering the results, but it counts the original rows, not the resulting rows after the first GROUP BY instance, version.
Any hint on how to achieve this?
Assuming that abbreviated results are stored in temp table test. Following query will give you the expected output.
select * from test where (instance,version)in
(select instance,max(version) as version from test A where exists
(select max(version) as version from test B where A.instance=B.instance and A.version<B.version group by instance) group by instance)
Ouput
instance version cnt
1021 18.2 422
1195 19.2 545
1196 18.3 844
1201 19.2 203
1208 18.3 31
1211 18.2 341
It seems you need (no optimization!)
WITH
cte1 AS ( SELECT instance, version, COUNT(id) AS cnt
FROM actions
WHERE status=0
AND version IS NOT NULL
GROUP BY instance, version ),
cte2 AS ( SELECT instance, MAX(version) version
FROM cte1
GROUP BY instance ),
cte3 AS ( SELECT instance, MAX(version) version
FROM cte1
LEFT JOIN cte2 USING (instance, version)
WHERE cte2.instance IS NULL
GROUP BY instance )
SELECT cte1.*
FROM cte1
JOIN cte3 USING (instance, version)
fiddle
You can use window functions:
SELECT iv.*
FROM (SELECT instance, version, COUNT(id) AS cnt,
ROW_NUMBER() OVER (PARTITION BY instance ORDER BY version DESC) as seqnum
FROM actions
WHERE status = 0 AND
version IS NOT NULL
GROUP BY instance, version
) iv
WHERE seqnum = 2;

How can I club values in MySql

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'

How can I specify the base level of a factor variable?

I have data for 2000-2016 and I am trying to estimate the following regression:
xtset id
xtreg lnp i.year i.year#fp, fe vce(robust)
However, when I do this, Stata omits 2008 because of collinearity.
Is there a way to specify which year is omitted?
More generally, you can specify the omitted level of a factor variable (i.e. the
base) by using the ib operator (see also help fvvarlist).
Below is a reproducible example using Stata's toy dataset nlswork:
webuse nlswork, clear
xtset idcode
Using 77 as the base year:
xtreg ln_wage ib77.year age, fe vce(robust)
Fixed-effects (within) regression Number of obs = 28,510
Group variable: idcode Number of groups = 4,710
R-sq: Obs per group:
within = 0.1060 min = 1
between = 0.0914 avg = 6.1
overall = 0.0805 max = 15
F(15,4709) = 69.49
corr(u_i, Xb) = 0.0467 Prob > F = 0.0000
(Std. Err. adjusted for 4,710 clusters in idcode)
------------------------------------------------------------------------------
| Robust
ln_wage | Coef. Std. Err. t P>|t| [95% Conf. Interval]
-------------+----------------------------------------------------------------
year |
68 | -.108365 .1111117 -0.98 0.329 -.3261959 .1094659
69 | -.0335029 .0995142 -0.34 0.736 -.2285973 .1615915
70 | -.0604953 .0867605 -0.70 0.486 -.2305866 .1095959
71 | -.0218073 .0742761 -0.29 0.769 -.1674232 .1238087
72 | -.0226893 .0622792 -0.36 0.716 -.1447857 .0994071
73 | -.0203581 .049851 -0.41 0.683 -.1180894 .0773732
75 | -.0305043 .0259707 -1.17 0.240 -.081419 .0204104
78 | .0225868 .0147272 1.53 0.125 -.0062854 .0514591
80 | .0058999 .0381391 0.15 0.877 -.0688706 .0806704
82 | .0006801 .0622403 0.01 0.991 -.1213399 .1227001
83 | .0127622 .074435 0.17 0.864 -.1331653 .1586897
85 | .0381987 .0989316 0.39 0.699 -.1557535 .2321508
87 | .0298993 .1237839 0.24 0.809 -.2127751 .2725736
88 | .0716091 .1397635 0.51 0.608 -.2023927 .345611
|
age | .0125992 .0123091 1.02 0.306 -.0115323 .0367308
_cons | 1.312096 .3453967 3.80 0.000 .6349571 1.989235
-------------+----------------------------------------------------------------
sigma_u | .4058746
sigma_e | .30300411
rho | .64212421 (fraction of variance due to u_i)
------------------------------------------------------------------------------
Using 80 as the base year:
xtreg ln_wage ib80.year age, fe vce(robust)
Fixed-effects (within) regression Number of obs = 28,510
Group variable: idcode Number of groups = 4,710
R-sq: Obs per group:
within = 0.1060 min = 1
between = 0.0914 avg = 6.1
overall = 0.0805 max = 15
F(15,4709) = 69.49
corr(u_i, Xb) = 0.0467 Prob > F = 0.0000
(Std. Err. adjusted for 4,710 clusters in idcode)
------------------------------------------------------------------------------
| Robust
ln_wage | Coef. Std. Err. t P>|t| [95% Conf. Interval]
-------------+----------------------------------------------------------------
year |
68 | -.1142649 .1480678 -0.77 0.440 -.4045471 .1760172
69 | -.0394028 .136462 -0.29 0.773 -.3069323 .2281266
70 | -.0663953 .1237179 -0.54 0.592 -.3089402 .1761497
71 | -.0277072 .1112026 -0.25 0.803 -.2457164 .190302
72 | -.0285892 .0991208 -0.29 0.773 -.2229124 .165734
73 | -.026258 .0866489 -0.30 0.762 -.1961303 .1436142
75 | -.0364042 .0625743 -0.58 0.561 -.1590791 .0862706
77 | -.0058999 .0381391 -0.15 0.877 -.0806704 .0688706
78 | .0166869 .0258678 0.65 0.519 -.0340261 .0673999
82 | -.0052198 .0257713 -0.20 0.840 -.0557437 .0453041
83 | .0068623 .0378166 0.18 0.856 -.0672759 .0810005
85 | .0322987 .0620538 0.52 0.603 -.0893558 .1539533
87 | .0239993 .0868397 0.28 0.782 -.1462471 .1942457
88 | .0657092 .1028815 0.64 0.523 -.1359868 .2674052
|
age | .0125992 .0123091 1.02 0.306 -.0115323 .0367308
_cons | 1.317996 .3824809 3.45 0.001 .5681546 2.067838
-------------+----------------------------------------------------------------
sigma_u | .4058746
sigma_e | .30300411
rho | .64212421 (fraction of variance due to u_i)
------------------------------------------------------------------------------

MYSQL filter our same rows that are next to each other

I have this table, similar to the one below.
Table show player points:
s main player points
d sub main points;
date when it is calculated.
I want to be able to filter rows that are same as s and d staying next to each other. Date should be as the last last one that are the same.
For example, here we should skip ri - 13 as it is the same as ri -12. Also skip ri - 15,19,20,21,22,23 and so on. But rows 28, 29,30,31 should not be skipped and grouped.
I'm asking because GROUP BY for my case do not work. Any ideas?
Table example:
ri date s d
1 2016-05-23 4 355
2 2016-05-16 4 352
3 2016-05-09 4 349
4 2016-05-02 4 352
5 2016-04-25 4 358
6 2016-04-18 4 359
7 2016-04-11 4 200
8 2016-04-04 4 201
9 2016-03-21 4 198
10 2016-03-07 4 199
11 2016-02-29 4 201
12 2016-02-22 4 203
13 2016-02-15 4 203
14 2016-02-08 4 200
15 2016-02-01 4 200
16 2016-01-18 4 201
17 2016-01-11 4 198
18 2016-01-04 4 183
19 2015-12-28 4 183
20 2015-12-21 4 183
21 2015-12-14 4 183
22 2015-12-07 4 183
23 2015-11-30 4 183
24 2015-11-23 4 182
25 2015-11-16 4 149
26 2015-11-09 4 148
27 2015-11-02 4 145
28 2015-10-26 4 109
29 2015-10-19 4 110
30 2015-10-12 4 109
31 2015-10-05 4 110
32 2015-09-28 4 106
33 2015-09-21 4 108
34 2015-09-14 4 109
35 2015-08-31 5 108
36 2015-08-24 5 108
37 2015-08-17 5 136
38 2015-08-10 5 136
39 2015-08-03 4 123
40 2015-07-27 4 122
41 2015-07-20 4 125
42 2015-07-13 4 126
43 2015-06-29 4 130
44 2015-06-22 4 128
45 2015-06-15 4 126
46 2015-06-08 4 120
47 2015-05-25 9 120
48 2015-05-18 9 122
49 2015-05-11 9 121
50 2015-05-04 9 119
51 2015-04-27 9 122
52 2015-04-20 10 124
53 2015-04-13 9 173
54 2015-04-06 9 172
55 2015-03-23 8 174
56 2015-03-09 7 89
57 2015-03-02 7 89
58 2015-02-23 7 92
59 2015-02-16 7 96
60 2015-02-09 8 93
61 2015-02-02 9 88
62 2015-01-19 4 89
63 2015-01-12 4 89
64 2015-01-05 4 94
Coulb be you need a join ..
select a.*, b.*
from my_table as a
inner join my_table as b on a.ri != b.ri
where (a.d - b.d) = 0;
This can be done using not exists. This would select the first of many rows which have the same s and d.
select *
from tablename t1
where not exists (select 1 from tablename t2
where t1.ri = t2.ri+1 and t1.s = t2.s and t1.d = t2.d)