In MySQL database, I have table with YEAR, MONTH, DAY columns.
| YEAR | MONTH | DAY | VALUE |
|----------------------------|
| 2018 | 11 | 9 | 1056 |
| 2018 | 11 | 10 | 6582 |
|****************************|
| 2018 | 12 | 9 | 6892 |
| 2018 | 12 | 10 | 5987 |
|****************************|
| 2019 | 3 | 5 | 5693 |
| 2019 | 3 | 6 | 5698 |
I need to take all values from the table between 2 date.
Let's say between 2018-11-09 and 2019-03-05 or between 2018-11-10 and 2018-12-09.
I need to say that unfortunately I can't merge these three column for one datetime column. Also the table has partitioning by that 3 columns.
Datatype of columns: smallint(6)
It seems this query should give you the results you want. It creates a date string out of your 3 columns and then uses STR_TO_DATE to convert that into a value that MySQL can compare with the search date strings.
SELECT *
FROM table1
WHERE STR_TO_DATE(CONCAT_WS('/', `DAY`, `MONTH`, `YEAR`), '%d/%m/%Y') BETWEEN '2018-11-09' AND '2019-03-05'
Output
YEAR MONTH DAY VALUE
2018 11 9 1056
2018 11 10 6582
2018 12 9 6892
2018 12 10 5987
2019 3 5 5693
Demo on dbfiddle
One way is to create a string in MySQL Date format (YYYY-MM-DD) using string functions such as Concat() and Lpad():
SELECT *
FROM your_table
WHERE CONCAT(`YEAR`, '-', LPAD(`MONTH`,2,'0'), '-', LPAD(`DAY`,2,'0'))
BETWEEN '2018-11-09' AND '2019-03-05'
Based on further discussion in comments, if you can input the year, month, and day value separately for the given data range(s); instead of creating a date using functions, we can directly use the respective columns instead. This will also allow us to utilize indexes (if defined) on these columns.
SELECT *
FROM your_table
WHERE
/* Condition for the month in the start date of the range */
(YEAR = 2018 AND MONTH = 11 AND DAY >= 9)
OR
/* Condition for the rest of the months in start date year */
(YEAR = 2018 AND MONTH > 11)
OR
/* Condition for the month in the end date of the range */
(YEAR = 2019 AND MONTH = 3 AND DAY <= 5)
OR
/* Condition for the rest of the months in end date year */
(YEAR = 2019 AND MONTH < 3)
OR
/* Condition for the years between the start and end date */
(YEAR > 2018 AND YEAR < 2019)
Above mentioned conditions can be compressed further. But I have written in this manner, for ease of understand-ability.
However, it is recommended to create another column to store the date in Date format. If you cannot make changes to the application code, and if your MySQL version >= 5.7, you can look at Generated Columns, and refer to that in your SELECT query instead.
ALTER TABLE your_table
ADD COLUMN date_col DATE
GENERATED ALWAYS AS CONCAT(`YEAR`, '-', LPAD(`MONTH`,2,'0'), '-', LPAD(`DAY`,2,'0')) STORED;
Then, the SELECT query becomes trivial:
SELECT * FROM your_table
WHERE date_col BETWEEN '2018-11-09' AND '2019-03-05'
Related
I have the following invoice data :
tbl_invoice :
+------------+--------+
| date | no_inv |
+------------+--------+
| 2021-01-02 | INV1 |
| 2015-01-02 | INV2 |
| 2013-01-01 | INV2 |
| 2021-01-05 | INV4 |
+------------+--------+
I want to display the last 3 months of data available even though it is different for different years, because my expected result is the last 3 months of data.
My Expectation Result :
In the invoice table from this figure, only date data are available in April 2020, May 2019 and June 2015.
I want to get the data for the last 3 months. How can SQL get results according to my expectations?
Assuming your date column is a datetime type, you can do this with a simple where.
You need to calculate the date 3 months ago, and filter to where date is greater than that. e.g.:
WHERE date > DATE_SUB(NOW(), INTERVAL 3 MONTH);
See the datetime arithmetic functions here:
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html
Solved with :
SELECT date
FROM invoice
GROUP BY MONTH(date)
ORDER BY date DESC
LIMIT 3
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 */
;
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
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.
With mysql i am trying to fetch amount which is donated last year only,
for exampe: this is my sample table. here i would like to fech amount which is donated in
last year only. here most recent donation is done on oct-14, so i want data from oct -14 to oct - 13 and not sep -13
+--------+-------+------+---------+
| nid | amount | time | month |
+--------+-------+------+---------+
| X | 30 | |sep-13 |
+--------+-------+------+---------+
| X | 30 | |sep-13 |
+--------+-------+------+---------+
| A | 10 | |oct-13 |
+--------+-------+------+---------+
| A | 10 | |oct-13 |
+--------+-------+------+---------+
| B | 20 | |oct-14 |
+--------+-------+------+---------+
| C | 20 | |oct-14 |
+--------+-------+------+---------+
If your 'month' column is a date column, you can use EXTRACT function.
SELECT * FROM _table_ WHERE EXTRACT(year from `month`) = 13;
SELECT * FROM TABLE WHERE RIGHT(MONTH, 2) = '13'
IF THE DATE LAST YEAR IS A STATIC VALUE AND WON'T NEED TO BE ADJUSTED FOR A YEAR TO YEAR PROJECT, WHETHER IT'S VARCHAR OR DATE THIS VALUE WILL BE TREATED AS A STRING AND THE RIGHT 2 CHARACTERS WILL REMAIN THE SAME. -Sorry about the caps.
If you're looking for a dynamic approach...
SELECT * FROM TABLE WHERE STR_TO_DATE(MONTH, '%Y') = YEAR(CURDATE() - 1)
OR something like the above. Again, this is dependent on the data type that defines that field. But this should do the trick.
If you need to return rows based on maximum year in table then one of these queries can help:
If month is DATE type:
SELECT *
FROM sample_table
WHERE YEAR(month) = YEAR((SELECT MAX(month) FROM sample_table))
If month is character type:
SELECT *
FROM sample_table
WHERE RIGHT(month,2) = (SELECT MAX(RIGHT(month,2)) FROM sample_table)