How to find the latest week and month from MySQL - mysql

This DEMO shows by month. And this DEMO shows by week. However I want to display
Q1: only this week of each student.
Q2: only this month of each student.
Q3: only last week of each student.
Q4: only last month of each student.
How can I achieve this?
CREATE TABLE `hw_homework` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`studentid` int(10) NOT NULL,
`subjectid` int(10) NOT NULL,
`assignment_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`teacherid` int(10) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ;
INSERT INTO `hw_homework` (`id`, `studentid`, `subjectid`, `assignment_name`, `teacherid`, `date`) VALUES
(1, 29, 5, '5E', 20, '2012-10-31 13:58:40'),
(2, 15, 5, '32B', 20, '2012-10-31 13:59:54'),
(3, 29, 4, 'Q2A', 20, '2012-10-30 17:53:46'),
(4, 29, 11, '6E', 20, '2012-10-02 20:06:39'),
(5, 29, 11, 'C15', 20, '2012-10-16 20:06:30'),
(6, 15, 11, '7A', 20, '2012-09-19 20:08:05'),
(7, 29, 5, '3B', 20, '2012-09-14 20:08:12'),
(8, 29, 13, '6E', 32, '2012-10-29 20:23:46'),
(9, 29, 11, '7E', 18, '2012-10-30 14:35:14'),
(10, 2, 5, '5E', 20, '2012-10-21 13:58:40'),
(11, 2, 5, '5E', 20, '2012-10-30 13:58:40'),
(12, 2, 5, '5E', 20, '2012-10-31 13:58:40');
By month
SELECT studentID,
DATE_FORMAT(`date`, '%M') `month`,
COUNT(studentID) totalMissed
FROM hw_homework
-- WHERE studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%M')
By week
SELECT studentID,
DATE_FORMAT(`date`, '%U') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework
-- WHERE studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%U')
Thanks in advance.

A1 :
SELECT studentID,
DATE_FORMAT(`date`, '%U') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework
WHERE DATE_FORMAT(`date`, '%U') = DATE_FORMAT(NOW(), '%U')
-- AND studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%U')
A2 :
SELECT studentID,
DATE_FORMAT(`date`, '%M') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework
WHERE DATE_FORMAT(`date`, '%M') = DATE_FORMAT(NOW(), '%M')
-- AND studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%M')
A3 :
SELECT studentID,
DATE_FORMAT(`date`, '%U') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework he
WHERE DATE_FORMAT(`date`, '%U') = (SELECT MAX(DATE_FORMAT(NOW(), '%U')) FROM hw_homework hi WHERE hi.studentID = he.studentID)
-- AND studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%U')
A4 :
SELECT studentID,
DATE_FORMAT(`date`, '%M') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework he
WHERE DATE_FORMAT(`date`, '%M') = (SELECT MAX(DATE_FORMAT(NOW(), '%M')) FROM hw_homework hi WHERE hi.studentID = he.studentID)
-- AND studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%M')

Related

MYSQL 5.6 get latest data of each user

My Database table is as shown below. I need to get latest mark of each student. Latest entry is the row with maximum udate and maximum oder. (The oder will be incremented by one on each entry with same date)
In my example, I have two students Mujeeb, Zakariya and two subjects ENGLISH, MATHS. I need to get latest mark of each student for each subject. My expectd result is as follows
My sample data is
DROP TABLE IF EXISTS `students`;
CREATE TABLE IF NOT EXISTS `students` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`udate` date NOT NULL,
`oder` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
`Subject` varchar(20) NOT NULL,
`mark` int(11) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=latin1;
INSERT INTO `students` (`uid`, `udate`, `oder`, `name`, `Subject`, `mark`) VALUES
(1, '2021-08-01', 1, 'Mujeeb', 'ENGLISH', 10),
(2, '2021-08-01', 1, 'Zakariya', 'ENGLISH', 20),
(3, '2021-08-10', 2, 'Mujeeb', 'ENGLISH', 50),
(4, '2021-08-11', 2, 'Zakariya', 'ENGLISH', 60),
(5, '2021-08-02', 1, 'Mujeeb', 'ENGLISH', 100),
(6, '2021-08-03', 1, 'Zakariya', 'ENGLISH', 110),
(7, '2021-08-10', 1, 'Mujeeb', 'ENGLISH', 500),
(8, '2021-08-11', 1, 'Zakariya', 'ENGLISH', 600),
(9, '2021-08-01', 2, 'Mujeeb', 'MATHS', 100),
(10, '2021-08-01', 2, 'Zakariya', 'MATHS', 75),
(11, '2021-08-10', 3, 'Mujeeb', 'MATHS', 50),
(12, '2021-08-11', 3, 'Zakariya', 'MATHS', 60);
Use NOT EXISTS:
SELECT s1.*
FROM students s1
WHERE NOT EXISTS (
SELECT 1
FROM students s2
WHERE s2.name = s1.name AND s2.Subject = s1.Subject
AND (s2.udate > s1.udate OR (s2.udate = s1.udate AND s2.oder > s1.oder))
);
Or with a correlated subquery in the WHERE clause:
SELECT s1.*
FROM students s1
WHERE s1.uid = (
SELECT s2.uid
FROM students s2
WHERE s2.name = s1.name AND s2.Subject = s1.Subject
ORDER BY s2.udate DESC, s2.oder DESC LIMIT 1
);
See the demo.
As ROW_NUMBER() function doesn't work at lower version of MySQL, So alternate way of row_number() is used for this solution.
-- MySQL (v5.6)
SELECT p.uid, p.udate, p.oder, p.name, p.Subject, p.mark
FROM (SELECT #row_no := IF((#prev_val = t.name && #prev_val1 = t.Subject), #row_no + 1, 1) AS row_number
, #prev_val := t.name AS name
, #prev_val1 := t.Subject AS Subject
, t.mark
, t.oder
, t.uid
, t.udate
FROM students t,
(SELECT #row_no := 0) x,
(SELECT #prev_val := '') y,
(SELECT #prev_val1 := '') z
ORDER BY t.name, t.Subject, t.udate DESC, t.oder DESC ) p
WHERE p.row_number = 1
ORDER BY p.name, p.Subject;
Please check the url http://sqlfiddle.com/#!9/b5befe/18

MYSQL Cumulative Totals with SUM and Subquery

I have the below table:
CREATE TABLE `_loans` (
`loan_id` int(11) NOT NULL,
`price` float(7,2) NOT NULL,
`term` int(11) NOT NULL,
`app_date` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `_loans` (`loan_id`, `price`, `term`, `app_date`) VALUES
(1, 299.00, 24, '2019-01-23'),
(2, 774.00, 24, '2019-01-24'),
(3, 817.80, 24, '2019-01-24'),
(4, 279.99, 24, '2019-01-28'),
(5, 463.99, 24, '2019-01-28'),
(6, 0.00, 24, '2019-01-28'),
(7, 357.00, 24, '2019-02-02'),
(8, 386.98, 24, '2019-02-04'),
(9, 846.00, 24, '2019-02-04'),
(10, 713.99, 24, '2019-02-06'),
(11, 0.00, 24, '2019-02-07'),
(12, 579.00, 24, '2019-02-11'),
(13, 179.00, 24, '2019-02-13'),
(14, 0.00, 24, '2019-02-19'),
(15, 259.00, 24, '2019-02-21'),
(16, 249.99, 24, '2019-02-26'),
(17, 319.00, 24, '2019-03-02'),
(18, 1108.99, 24, '2019-03-05'),
(19, 319.00, 24, '2019-03-05'),
(20, 199.97, 24, '2019-03-06');
ALTER TABLE `_loans`
ADD PRIMARY KEY (`loan_id`),
ADD KEY `app_date` (`app_date`);
And the below query, which gives a monthly summary of the table data:
SELECT
MONTHNAME(w.app_date) month,
YEAR(w.app_date) year,
COUNT(*) contracts,
SUM(w.total_price) totals,
#running_total := #running_total + SUM(w.total_price) running_totals
FROM (
SELECT
app_date,
SUM(price * term) total_price
FROM _loans l
GROUP BY l.loan_id
) w
JOIN (SELECT #running_total := 0) r
GROUP BY YEAR(w.app_date), MONTH(w.app_date)
ORDER BY YEAR(w.app_date), MONTH(w.app_date) ASC
I need a running total of the values from the 'totals' column. Everything works well except the cumulative total, which is not accumulating.
month | year | contracts | totals | running_totals
------------------------------------------------------------------
January | 2019 | 6 | 63234.72 | 63234.71923828125
February | 2019 | 10 | 85703.04 | 85703.04016113281
March | 2019 | 4 | 46727.04 | 46727.039794921875
This isn't working because of the GROUPing. You need to nest the GROUPing as a subquery and compute the running total from that:
SELECT monthname as month, year, contracts, totals,
#running_total := #running_total + totals AS running_totals
FROM (SELECT
MONTHNAME(w.app_date) monthname,
MONTH(w.app_date) monthnum,
YEAR(w.app_date) year,
COUNT(*) contracts,
SUM(w.total_price) totals
FROM (SELECT
app_date,
SUM(price * term) total_price
FROM _loans l
GROUP BY l.loan_id
) w
GROUP BY year, monthnum, monthname
) t
JOIN (SELECT #running_total := 0) r
ORDER BY year, monthnum ASC
Output:
month year contracts totals running_totals
January 2019 6 63234.72 63234.71923828125
February 2019 10 85703.04 148937.75939941406
March 2019 4 46727.04 195664.79919433594
Demo on dbfiddle
Your query is overly complicated. The subquery is not necessary for the aggregation. However, it is necessary for the use of variables:
SELECT month, year, total_price,
(#running_total := #running_total + total_price) as running_totals
FROM (SELECT MONTHNAME(l.app_date) as month,
YEAR(l.app_date) as year,
MONTH(l.app_date) as mon,
COUNT(DISTINCT l.loan_id) as contracts,
SUM(l.price * l.term) total_price
FROM _loans l
GROUP BY l.loan_id, YEAR(w.app_date), MONTH(w.app_date)
ORDER BY l.loan_id, YEAR(w.app_date), MONTH(w.app_date)
) l CROSS JOIN
(SELECT #running_total := 0) params
ORDER BY year, mon ASC

Select and show business open hours from MySQL

I dont need to check if business is open or close, but I need to show open hours by days.
There are some options:
1 - Business open once in day (sample - from 10:00 to 18:30) - one
rows in table
2 - Business open TWICE in day (samlpe - from 10:00 to
14:00 and from 15:00 to 18:30) - two rows in table
3 - Business may
be closed (no row inserted)
Here my MySql table of hours storing. In this sample business (affiliate_id) are open twice in days from 0 to 4, once in day 5 and closed in day 6 (no records for this day)
http://postimage.org/image/yplj4rumj/
What I need to show in website its like (according to this database example:
0,1,2,3,4 - open 10:00-14:00 and 15:00-18:30
5 - open 10:00-12:00
6 - closed
How I get results like:
http://postimage.org/image/toe53en63/
?
I tried to make queries with GROUPֹ_CONCAT and LEFT JOIN the same table ON a.day=b.day but with no luck :(
There sample of my query (that is wrong)
SELECT GROUP_CONCAT( DISTINCT CAST( a.day AS CHAR )
ORDER BY a.day ) AS days, DATE_FORMAT( a.time_from, '%H:%i' ) AS f_time_from, DATE_FORMAT( a.time_to, '%H:%i' ) AS f_time_to, DATE_FORMAT( b.time_from, '%H:%i' ) AS f_time_from_s, DATE_FORMAT( b.time_to, '%H:%i' ) AS f_time_to_s
FROM business_affiliate_hours AS a LEFT
JOIN business_affiliate_hours AS b ON a.day = b.day
WHERE a.affiliate_id =57
GROUP BY a.time_from, a.time_to, b.time_from, b.time_to
ORDER BY a.id ASC
This my table:
CREATE TABLE IF NOT EXISTS `business_affiliate_hours` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`affiliate_id` int(10) unsigned NOT NULL DEFAULT '0',
`time_from` time NOT NULL,
`time_to` time NOT NULL,
`day` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
INSERT INTO `business_affiliate_hours` (`id`, `affiliate_id`, `time_from`, `time_to`, `day`) VALUES
(53, 57, '10:00:00', '12:00:00', 5),
(52, 57, '15:00:00', '18:30:00', 4),
(51, 57, '10:00:00', '14:00:00', 4),
(50, 57, '15:00:00', '18:30:00', 3),
(49, 57, '10:00:00', '14:00:00', 3),
(48, 57, '15:00:00', '18:30:00', 2),
(47, 57, '10:00:00', '14:00:00', 2),
(46, 57, '15:00:00', '18:30:00', 1),
(45, 57, '10:00:00', '14:00:00', 1),
(44, 57, '15:00:00', '18:30:00', 0),
(43, 57, '10:00:00', '14:00:00', 0);
Open hours may be different for every day, so I want to GROUP by the same open hours, and get list of days for all unique order of open hours.
Need your help!
Sorry for links to images, I cant upload images yes to here.
First build a materialised table of each day's combined times, then group on that:
SELECT GROUP_CONCAT(day ORDER BY day) AS days,
DATE_FORMAT(f1, '%H:%i') AS f_time_from,
DATE_FORMAT(t1, '%H:%i') AS f_time_to,
DATE_FORMAT(f2, '%H:%i') AS f_time_from_s,
DATE_FORMAT(t2, '%H:%i') AS f_time_to_s
FROM (
SELECT day,
MIN(time_from) AS f1,
MIN(time_to ) AS t1,
IF(COUNT(*) > 1, MAX(time_from), NULL) AS f2,
IF(COUNT(*) > 1, MAX(time_to ), NULL) AS t2
FROM business_affiliate_hours
WHERE affiliate_id = 57
GROUP BY day
) t
GROUP BY f1, t1, f2, t2
ORDER BY days
See it on sqlfiddle.

How to find data from last week in MySQL

I want to display data from
Q1: only last week of each student.
Q2: only last month of each student.
How can I achieve this?
DEMO for week
DEMO for month
CREATE TABLE `hw_homework` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`studentid` int(10) NOT NULL,
`subjectid` int(10) NOT NULL,
`assignment_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`teacherid` int(10) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) ;
INSERT INTO `hw_homework` (`id`, `studentid`, `subjectid`, `assignment_name`, `teacherid`,
`date`) VALUES
(1, 29, 5, '5E', 20, '2012-11-04 13:58:40'),
(2, 15, 5, '32B', 20, '2012-11-04 13:59:54'),
(3, 29, 4, 'Q2A', 20, '2012-10-30 17:53:46'),
(4, 29, 11, '6E', 20, '2012-11-02 20:06:39'),
(5, 29, 11, 'C15', 20, '2012-10-16 20:06:30'),
(6, 15, 11, '7A', 20, '2012-09-19 20:08:05'),
(7, 29, 5, '3B', 20, '2012-09-14 20:08:12'),
(8, 29, 13, '6E', 32, '2012-10-29 20:23:46'),
(9, 29, 11, '7E', 18, '2012-10-30 14:35:14'),
(10, 2, 5, '5E', 20, '2012-10-21 13:58:40'),
(11, 2, 5, '5E', 20, '2012-10-30 13:58:40'),
(12, 2, 5, '5E', 20, '2012-10-31 13:58:40');
This does not work for last week. It shows this week result.
SELECT studentID,
DATE_FORMAT(`date`, '%U') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework he
WHERE DATE_FORMAT(`date`, '%U') = (SELECT MAX(DATE_FORMAT(NOW(), '%U')) FROM hw_homework hi WHERE hi.studentID = he.studentID)
-- AND studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%U')
This does not work for last month. This shows this month result.
SELECT studentID,
DATE_FORMAT(`date`, '%M') `Month`,
COUNT(studentID) totalMissed
FROM hw_homework he
WHERE DATE_FORMAT(`date`, '%M') = (SELECT MAX(DATE_FORMAT(NOW(), '%M')) FROM hw_homework hi WHERE hi.studentID = he.studentID)
-- AND studentID = ''
GROUP BY studentID, DATE_FORMAT(`date`, '%M')
Thanks in advance.
try subtracting 1 from weekNo:
SELECT studentID,
DATE_FORMAT(`date`, '%U') `WeekNo`,
COUNT(studentID) totalMissed
FROM hw_homework he
WHERE DATE_FORMAT(`date`, '%U') =
(SELECT MAX(DATE_FORMAT(NOW(), '%U')-1)
FROM hw_homework hi
WHERE hi.studentID = he.studentID)
GROUP BY studentID, DATE_FORMAT(`date`, '%U')

How to sort by month in MySQL

Here is demo
The order is November and October. How can I add ORDER BY to this, so that the order is by month, Jan, Feb, Mar...etc.
Thanks in advance.
CREATE TABLE `hw_homework` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`studentid` int(10) NOT NULL,
`subjectid` int(10) NOT NULL,
`assignment_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`teacherid` int(10) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=55 ;
--
-- Dumping data for table `hw_homework`
--
INSERT INTO `hw_homework` (`id`, `studentid`, `subjectid`, `assignment_name`, `teacherid`, `date`) VALUES
(52, 56, 13, '1A', 20, '2012-10-28'),
(53, 56, 6, '12', 18, '2012-10-28'),
(54, 56, 4, 'page42', 59, '2012-11-02');
SELECT studentID,
DATE_FORMAT(`date`,'%M') `month`,
COUNT(studentid) totalMissed
FROM hw_homework
WHERE studentid = 56
GROUP BY studentid, DATE_FORMAT(`date`, '%M')
As Chuidiang suggested I added the following to get what I wanted.
Thanks everyone.
ORDER BY Month(date)
In your case it is ordering based on aplhabets.
Following will give correct result.
SELECT studentID,
DATE_FORMAT(`date`,'%M') `month`,
COUNT(studentid) totalMissed
FROM hw_homework
WHERE studentid = 56
GROUP BY studentid, DATE_FORMAT(`date`, '%M')
ORDER BY DATE_FORMAT(`date`,'%m')
Stumbled across this post trying to find the solution to sort by Month name. Probably not very elegant solution, but you can use the FIELD string function to get that result set.
SELECT
studentID,
DATE_FORMAT(`date`, '%M') `month`,
COUNT(studentid) totalMissed FROM
hw_homework WHERE
studentid = 56 GROUP BY
studentid,
DATE_FORMAT(`date`, '%M') ORDER BY
FIELD(
DATE_FORMAT(`date`, '%M'),
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
);
Try that. Also you can perhaps replace DATE_FORMAT with the easier function MONTHNAME(date) for readability purposes.
SELECT studentID,
DATE_FORMAT(`date`,'%M') as `month`,
COUNT(studentid) totalMissed
FROM hw_homework
WHERE studentid = 56
order by Month(month)
GROUP BY studentid, DATE_FORMAT(`date`, '%M')
SELECT studentID,
DATE_FORMAT(`date`,'%M') `month`,
COUNT(studentid) totalMissed
FROM hw_homework
WHERE studentid = 56
GROUP BY MONTH(DATE) ASC
Use as follows in your query
GROUP BY MONTH(date)
mysql> select * from hw_homework order by date asc; //increasing order
OR
mysql> select * from hw_homework order by date desc;