How to select some rows as columns in mysql - mysql

Hello guys? I am working with a MySQL table that stores employees payno, date and meter readings for electricity. I want to select readings for a previous month as previous month reading and current month reading as current month reading, this is what I mean
payno | date | value
-------+------------+------------
6 | 2019-08-31 | 2477
6 | 2019-09-25 | 2487
8 | 2019-08-31 | 1651.2
8 | 2019-09-25 | 1697.6
Above is the structure of my table, I want to achieve something like this:
payno | previous month| current month
-------+---------------+------------
6 | 2477 | 2487
8 | 1651.2 | 1697.6
Notice that the previous month reading are the readings having month(date) as 8 and the current month readings have month(date) as 9.

I don't know how many readings can be per month, so we'll summarize them.
select e.payno,
( select sum(x1.val)
from emp x1
where x1.payno=e.payno and month(x1.data)=month(date_sub(e.data, INTERVAL 1 MONTH))
group by x1.payno ) AS prev_month,
( select sum(x2.val)
from emp x2
where x2.payno=e.payno and month(x2.data)=month(e.data)
group by x2.payno ) AS this_month
from emp e
where month(e.data)=9 /* this is where you specify "current" month */
;

Related

MYSQL - Finding row delta using date rows that include holidays

I have a table that includes a field with dates (call it date) and a field with a cumulative running total (call it X) | call it table SAMPLE.
***My data in field DATE does not include weekends and holidays.
I can find the delta in the numbers from day to day by simply subtracting any chosen value in "X" and subtracting that from the row above.
Here's my current query:
select
date,
a.X - b.X as 'Daily Total'
from SAMPLE as a
left join SAMPLE as b
on b.date = if(weekday(a.date) = 0 , a.date - interval 3 day, a.date- interval 1 day);
The problem is that the above values work until I hit dates with holidays. If Monday is a holiday, then the values return null because a.date - interval 1 day will not exist. What's the best way to go about solving the holidays issue?
the below are the current results:
+------------+---------------+
| date | X |
+------------+---------------+
| 2018-03-26 | -40105.00 |
| 2018-03-27 | 28470.00 |
| 2018-03-28 | 5265.00 |
| 2018-03-29 | -23010.00 |
| 2018-04-02 | NULL |
| 2018-04-03 | -24830.00 |
| 2018-04-04 | -21970.00 |
| 2018-04-05 | -9620.00 |
| 2018-04-06 | 36465.00 |
Thanks in advance!!
I will sort the table by date then assign a sequence or series of numbers from 1 to n. I will then subtract the value of current row from the previous row except the first row. For first row, i will copy the value X.
select rnk2.`date`,
case when rnk1.r1=1 and rnk2.r2=1 then rnk1.X else rnk2.X-rnk1.X end as 'Daily Total'
from (
select `date`,X,#r1:=#r1+1 as r1
from samples, (select #r1:=0) a
order by `date` ) rnk1
inner join
(select `date`,X,#r2:=#r2+1 as r2
from samples, (select #r2:=0) b
order by `date`) rnk2
on (rnk1.r1=1 and rnk2.r2=1) or (rnk1.r1+1=rnk2.r2)
order by rnk2.`date`

SQL group: count multiple things

Right now I've got the following (My)SQL-Statement which returns the amount of entrys based on hour.
SELECT
COUNT(*) AS amount
HOUR(date) AS hour
-- [1]
FROM
table
GROUP BY
HOUR(date)
But I actually want another result that contains the amount of days the hour appeared. Basicly something like:
[1] = COUNT(DAY(date), MONTH(date), YEAR(date)) AS day_count
Example:
id | date
0 | 01/01/2001 5:15
1 | 01/01/2001 5:10
2 | 01/01/2001 6:03
3 | 01/01/2001 7:04
4 | 02/01/2001 5:00
Should return
amount | hour | day_count
3 | 5 | 2
1 | 6 | 1
1 | 7 | 1
I think you just need to part out the days by hour and day, and group by them...
SELECT count(*) as `amount`
, count(hour(date)) as `Hour`
, count(day(date)) as `Day_Count`
FROM table
GROUP BY hour(Date), day(date)

Obtain a list of month and records from the current date(month) in two different years

I have such a set of records in a table in a mysql database;
Date | Number_of_leaves
10th-December-2015 | 10 leaves
6th-August-2015 | 10 leaves
15th-September-2015 | 14 leaves
15th-January-2016: | 100 leaves
7th-November-2015: | 4 leaves
9th-October -2015: | 200 leaves
How can i return a list months and their records for just the past 4 months from Jan-2016 backwards? In other words, i need a result for the past 4 months including the current one like this:
January 2016 | 100 leaves
December 2015 | 10 leaves
November 2015 | 4 leaves
October 2015 | 200 leaves
The above is the kind of result which shows the month and the corresponding year with the number of leaves collected in that month and corresponding year
Schema
create table xyz
( id int auto_increment primary key,
theDate date not null,
leaves int not null
);
-- truncate table xyz;
insert xyz(theDate,leaves) values
('2016-04-10',444510),
('2016-02-10',55510),
('2015-12-10',10),
('2015-08-06',10),
('2015-09-15',14),
('2016-01-15',100),
('2015-11-07',4),
('2015-10-09',200);
Query 1
select month(theDate) as m,
year(theDate) as y,
sum(leaves) as leaves
from xyz
where theDate<='2016-02-01'
group by month(theDate),year(theDate)
order by theDate desc
limit 4;
or
Query 2
select concat(monthname(theDate),' ',year(theDate)) as 'Month/Year',
sum(leaves) as leaves
from xyz
where theDate<='2016-02-01'
group by month(theDate),year(theDate)
order by theDate desc
limit 4;
+---------------+--------+
| Month/Year | leaves |
+---------------+--------+
| January 2016 | 100 |
| December 2015 | 10 |
| November 2015 | 4 |
| October 2015 | 200 |
+---------------+--------+
op is your table name first use str_to_date for convert string to date format .we use if because your date format is different
select * FROM (
SELECT *,
IFNULL(
IFNULL(
str_to_date(Date,'%D-%b-%Y'),str_to_date(Date,'%d-%M-%Y')) ,
str_to_date(Date,'%D-%M-%Y')
)
f_date
FROM `op`
order by number_of_leaves DESC,f_date ASC
) tab
group by month(tab.f_date) LIMIT 5

MySQL: Calculate 4 Week Average with 4 Week Offset

This question is related to a post I made earlier: MySQL: Calculating Data from Table with One Month Offset
But now I need to build a procedure that queries a table of contact data stored by week. Here's a simplified example of the table I am working with:
+-----------------+------------+
| week_start_date | contacts |
+-----------------+------------+
| 2015-03-08 | 12 |
| 2015-03-01 | 20 |
| 2015-02-22 | 5 |
| 2015-02-15 | 17 |
| 2015-02-08 | 8 |
| 2015-02-01 | 2 |
| 2015-01-25 | 16 |
| 2015-01-18 | 10 |
| 2015-01-11 | 4 |
| ... | ... |
+-----------------+------------+
What I need to figure out is how to calculate a 4 week moving average that also has a 4 week offset on top of that. For instance, if I wanted to get the average contacts for the week of March 8, 2015, it would be the average of January 18 through February 8. In the example above, my average would be: (10 + 16 + 2 + 8 ) / 4 = 9. And if I wanted to find the average for the week of March 1, 2015, then it would be the average of January 11 through February 1 which comes out to be 8 using the sample table above.
From my last post, I know that I can handle the 4 week offset by joining the table with itself on the week_start_date similar to this:
SELECT s1.week_start_date, s2.Total_Contacts
FROM sample_table s1
LEFT JOIN (SELECT week_start_date, sum(contacts) AS Total_Contacts
FROM sample_table
GROUP BY week_start_date) s2
ON s1.week_start_date =
date_add(s2.week_start_date, INTERVAL 4 WEEK)
WHERE s1.week_start_date = '2015-03-08'
GROUP BY s1.week_start_date;
But getting it to compute the four week average as well is where I am stuck. I thought joining it on a range of dates would work, but I keep getting averages that are a lot larger than expected. I'm guessing it is due to how the week_start_date's are being grouped. (Note that there can be multiple records for each week. I only show one record for each week on the sample table to make it less cluttered.)
Is joining on a date range the correct approach? Or do I need to add another join somewhere?
Thanks for your help.
I would suggest using a correlated subquery:
select st.*,
(select avg(contacts)
from sample_table st2
where st2.week_start_date >= st.week_start_date - interval 7 * 7 days and
st2.week_start_date <= st.week_start_date - interval 4 * 7 days
) as avg_4week_delayed
from sample_table st;
I would use the DATE_SUB() function and just subtract the necessary weeks you need. So, for March 8 in your example, try something like this:
SELECT AVG(contacts)
FROM myTable
WHERE week_start_date <= DATE_SUB('2015-03-08', INTERVAL 4 WEEK) AND week_start_date >= DATE_SUB('2015-03-08', INTERVAL 7 WEEK);
It worked in SQL Fiddle.

MySQL get records what have max value

This is my table named period.
id | year | month
222 | 2014 | 2
345 | 2013 | 5
33 | 2014 | 1
224 | 2014 | 2
I want get only id what have latest month (2014-02). Result should be 222, 224.
I wrote following query.
SELECT id, MAX(year*100 + month) FROM period
But it is returning following result.
222| 201402
How can i get my result
SELECT x.*
FROM period x
JOIN
( SELECT year
, month
FROM period
ORDER
BY year DESC
, month DESC
LIMIT 1
) y
ON y.year = x.year
AND y.month = x.month;
You should you the following query:---
SELECT id FROM period where year=(SELECT max(year) from period) and month=(SELECT max(month) from period);