how to get records count of this month?
I want to count user of this month ? "this month" should be calculate by mysql itself. how to write the sql?
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `a`
-- ----------------------------
DROP TABLE IF EXISTS `a`;
CREATE TABLE `a` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(30) default NULL,
`date` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of a
-- ----------------------------
INSERT INTO `a` VALUES ('1', 'jimy', '2014-02-11 09:24:42');
INSERT INTO `a` VALUES ('7', 'khon', '2014-02-19 09:24:50');
INSERT INTO `a` VALUES ('3', 'tina', '2014-01-11 09:25:03');
INSERT INTO `a` VALUES ('4', 'kelvin', '2013-12-11 09:25:09');
INSERT INTO `a` VALUES ('5', 'ricky', '2014-02-12 09:25:14');
you can try this
Select count(*)
FROM a
WHERE MONTH(date) = MONTH(NOW())
GROUP BY MONTH(date)
MONTH(date) only returns the month number, it won't work with multiple years data.
SELECT COUNT(*) count
FROM a
WHERE EXTRACT(YEAR_MONTH FROM a.date) = EXTRACT(YEAR_MONTH FROM NOW())
Or you could use:
SELECT COUNT(*) count
FROM a
WHERE DATE_FORMAT(a.date,'%Y%m') = DATE_FORMAT(NOW(),'%Y%m')
Related
I have a source table (TableA) that contains multiple records for each day. I need to left join (on the date field) it to TableB that contains a few records per year.
The problem is that TableA should be joined to the earliest record from TableB where the date from TableA <= the date from TableB.
CREATE TABLE IF NOT EXISTS `tableA` (
`id` int(6) unsigned NOT NULL,
`date` date NOT NULL,
`content` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `tableA` (`id`, `date`, `content`) VALUES
('1', '2017-10-03', 'The earth is round.'),
('2', '2018-01-01', 'The earth is flat'),
('3', '2018-01-01', 'One hundred angels can dance on the head of a pin'),
('4', '2018-01-02', 'The earth is flat and rests on a bull\'s horn'),
('5', '2018-01-03', 'The earth is like a ball.');
CREATE TABLE IF NOT EXISTS `tableB` (
`date` date NOT NULL,
`content` varchar(200) NOT NULL,
PRIMARY KEY (`date`)
) DEFAULT CHARSET=utf8;
INSERT INTO `tableB` (`date`, `content`) VALUES
('2017-01-01', 'ONE'),
('2017-12-01', 'TWO'),
('2018-01-02', 'THREE'),
('2018-01-05', 'FOUR');
Based on the this SQLFiddle, I'm looking for the following result.
tableA.id | tableB.content
--------------------------
1 | TWO
2 | THREE
3 | THREE
4 | THREE
5 | FOUR
Here is one solution:
SELECT a.id, b.content
FROM TableA a
JOIN TableB b ON b.date = (
SELECT MIN(b2.date)
FROM TableB b2
WHERE b2.date >= a.date
);
I'm not sure whether this is the most efficient way, but it works.
Hi I want a SQL statement that would return all courses
having at least 2 students enrolled which is ordered by course with the
greatest number of students. I am pretty new with SQL stuff and I am finding it bit difficult.
here is my current database
CREATE TABLE `course` (
`CourseID` char(11) NOT NULL,
`Course_name` varchar(22) DEFAULT NULL,
`hours_per_week` varchar(22) DEFAULT NULL,
`Start_date` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `course`
--
INSERT INTO `course` (`CourseID`, `Course_name`, `hours_per_week`, `Start_date`) VALUES
('C001', 'Cert 1', '15', '2012-02-01'),
('C002', 'Cert 2', '20', '2012-02-02'),
('C003', 'Cert 3', '16', '2012-02-03'),
('C004', 'Cert 4', '20', '2012-02-13');
-- --------------------------------------------------------
--
-- Table structure for table `enrolment`
--
CREATE TABLE `enrolment` (
`studentID` char(11) NOT NULL,
`courseID` char(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `enrolment`
--
INSERT INTO `enrolment` (`studentID`, `courseID`) VALUES
('S001', 'C001'),
('S002', ' C001'),
('S003', ' C002'),
('S004', ' C002'),
('S005', ' C004');
-- --------------------------------------------------------
--
-- Table structure for table `student`
--
CREATE TABLE `student` (
`StudentID` char(11) NOT NULL,
`FirstName` varchar(22) DEFAULT NULL,
`LastName` varchar(22) DEFAULT NULL,
`DOB` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `student`
--
INSERT INTO `student` (`StudentID`, `FirstName`, `LastName`, `DOB`) VALUES
('S001', 'Alison', 'Tildesley', '1984-05-09'),
('S002', 'Fred', 'Nile', '1940-03-03'),
('S003', 'Christine', 'Anu', '1970-09-01'),
('S004', 'Jame', 'Brown', '1976-02-03'),
('S005', 'Mark', 'Oliphant', '1958-03-10'),
('S006', 'George', 'Bush', '1951-11-28');
This is what I have tried
SELECT FROM COURSES WHERE STUDENT_ID >=2
I know I have to add student_id row into my course table but I am still confused how to get desired results. I am sorry I am very new to database and MYSQL statements.
This should do:
SELECT C.CourseID, C.Course_name, COUNT(E.StudentID) Students_num
FROM course C
JOIN enrolment E USING(CourseID)
GROUP BY C.CourseID, C.Course_name
HAVING Students_num >= 2
ORDER BY Students_num DESC, C.Course_name
This will extract all courses joined with their enrollment records, and then group them by the course ID and name, counting the number of students; the last HAVING clause will discard all records that, after the grouping, will have less than 2 students.
Here is a working SQL fiddle for testing.
Not tested ;)
select
c.courseID, count(0)
from course c, enrolment e
where c.CourseID = e.CourseID
group by
c.courseID
having
count(0) >= 2
order by
count(0) desc
This is more of a concept question I guess.
* discussion
discussionId
message
timestamp
* comment
commentId
message
timestamp
* tweet
tweetId
message
timestamp
Then on a page I list the first let's say 10 entries and with next will load the next 10. All normal there.
My question is: Is there a way to limit each query of the UNION or I can only do the LIMIT/OFFSET on the result of the UNION? I'm pondering because I was imagining if each table has like 1K (I know the number is very low), the query would return 3K results and then grab only 10. When the number of rows gets bigger, it wouldn't slow down the performance? Or even if in the future there are more tables that I want to do the UNION, it wouldn't be better to get x of each one of then and in the end get the desired 10? But I can't figure it out how I'll know which one was the last one of the limit/offset of the queries... so I'm afraid I would have to select all and use the limit on the UNION.
So instead of using
(SELECT
message,
timestamp
FROM
discussion
)
UNION
(SELECT
message,
timestamp
FROM
comment
)
UNION
(SELECT
message,
timestamp
FROM
tweet
)
LIMIT $offset, $limit
Is it possible to have
(SELECT
message,
timestamp
FROM
discussion
LIMIT $offset, $limit
)
UNION
(SELECT
message,
timestamp
FROM
comment
LIMIT $offset, $limit
)
UNION
(SELECT
message,
timestamp
FROM
tweet
LIMIT $offset, $limit
)
LIMIT $offset, $limit
Thanks for your help!
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Message
(`id` int, `type_id` int, `message` varchar(10), `timestamp` int)
;
INSERT INTO Message
(`id`, `type_id`, `message`, `timestamp`)
VALUES
(1, 1, 'message1', 12345678),
(2, 2, 'message2', 12345679),
(3, 3, 'message3', 12345680)
;
CREATE TABLE Type
(`id` int, `type` varchar(10))
;
INSERT INTO Type
(`id`, `type`)
VALUES
(1, 'discussion'),
(2, 'comment'),
(3, 'tweet')
;
CREATE TABLE DiscussionDetail
(`id` int, `message_id` int, `from_user` varchar(10), `to_user` varchar(10))
;
INSERT INTO DiscussionDetail
(`id`, `message_id`, `from_user`, `to_user`)
VALUES
(1, 1, 'Peter', 'Anna')
;
CREATE TABLE CommentDetail
(`id` int, `message_id` int, `post_id` varchar(5), `user_id` varchar(5))
;
INSERT INTO CommentDetail
(`id`, `message_id`, `post_id`, `user_id`)
VALUES
(1, 2, 'post4', 'user6')
;
CREATE TABLE TweetDetail
(`id` int, `message_id` int, `twitteracct` varchar(6))
;
INSERT INTO TweetDetail
(`id`, `message_id`, `twitteracct`)
VALUES
(1, 3, 'myacct')
;
Query 1:
SELECT Message.*, type,
case when dd.id is not null then from_user
when cd.id is not null then post_id
when td.id is not null then twitteracct else '' end as detail1,
case when dd.id is not null then to_user
when cd.id is not null then user_id else '' end as detail2
FROM Message
INNER JOIN Type ON Type_Id = Type.id
LEFT OUTER JOIN DiscussionDetail dd ON dd.message_id = Message.id AND Type_Id = 1
LEFT OUTER JOIN CommentDetail cd ON cd.message_id = Message.id AND Type_Id = 2
LEFT OUTER JOIN TweetDetail td ON td.message_id = Message.id AND Type_Id = 3
ORDER BY timestamp LIMIT 1,1
Results:
| id | type_id | message | timestamp | type | detail1 | detail2 |
|----|---------|----------|-----------|---------|---------|---------|
| 2 | 2 | message2 | 12345679 | comment | post4 | user6 |
You can also create a VIEW for this :
CREATE VIEW AllMessages AS
SELECT Message.*, type,
case when dd.id is not null then from_user
when cd.id is not null then post_id
when td.id is not null then twitteracct else '' end as detail1,
case when dd.id is not null then to_user
when cd.id is not null then user_id else '' end as detail2
FROM Message
INNER JOIN Type ON Type_Id = Type.id
LEFT OUTER JOIN DiscussionDetail dd ON dd.message_id = Message.id AND Type_Id = 1
LEFT OUTER JOIN CommentDetail cd ON cd.message_id = Message.id AND Type_Id = 2
LEFT OUTER JOIN TweetDetail td ON td.message_id = Message.id AND Type_Id = 3
And then :
SELECT *
FROM AllMessages
ORDER BY timestamp LIMIT 1,1
SQL Fiddle
I like your question and I myself asked that once. I used the second solution of retrieving all and then paginate what I needed. Now, the problem is the performance, so here I will try to improve the performance of retrieving the rows, with several thousands of rows (this solution have to be tested, but I think it will work smoothly).
The tricky performance idea: Create a new table, only with ids of the tables, look for the timestamp (or the column that every table share and you use for ordering) and then filter by that. This way, you will have this:
SELECT insert_time
FROM all_tables_order
ORDER BY insert_time DESC
LIMIT 0,5
From there, you take the boundaries (First and last row result, to take the insert_time, you may see that in http://sqlfiddle.com/#!9/043c1/29), and then you create the big SQL, with that limits:
SELECT *
FROM (
SELECT t.id as id,
t.tweet as message,
t.insert_time as insert_time
FROM tweets t
WHERE insert_time <= '2015-08-06 21:53:30'
AND insert_time >= '2015-08-06 21:51:34'
UNION ALL
SELECT c.id as id,
c.`comment` as message,
c.insert_time as insert_time
FROM comments c
WHERE insert_time <= '2015-08-06 21:53:30'
AND insert_time >= '2015-08-06 21:51:34'
UNION ALL
SELECT m.id as id,
m.message as message,
m.insert_time as insert_time
FROM messages m
WHERE insert_time <= '2015-08-06 21:53:30'
AND insert_time >= '2015-08-06 21:51:34'
) AS myWholeTable
ORDER BY insert_time
This should be quite fast, despite the fact you're doing two queries, because your results are indexed, and you're only ordering small results: http://sqlfiddle.com/#!9/043c1/30
Your database schema should have something like the following, with the triggers there to update the indexes table:
Tables and datas:
CREATE TABLE IF NOT EXISTS `all_tables_order` (
`id` int(11) DEFAULT NULL,
`insert_time` timestamp NULL DEFAULT NULL,
`table_name` enum('comments','tweets','messages') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `all_tables_order` (`id`, `insert_time`, `table_name`) VALUES
(1, '2015-08-06 21:50:52', 'messages'),
(2, '2015-08-06 21:51:34', 'comments'),
(1, '2015-08-06 21:52:10', 'tweets'),
(2, '2015-08-06 21:52:46', 'messages'),
(2, '2015-08-06 21:53:07', 'tweets'),
(3, '2015-08-06 21:53:30', 'comments'),
(1, '2015-08-03 21:53:39', 'comments');
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`comment` tinytext CHARACTER SET latin1,
`insert_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY `Índice 1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=COMPACT;
INSERT INTO `comments` (`id`, `comment`, `insert_time`) VALUES
(2, 'c1', '2015-08-06 21:51:34'),
(3, 'c3', '2015-08-06 21:53:30'),
(1, 'c2', '2015-08-03 21:53:39');
CREATE TABLE IF NOT EXISTS `messages` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`message` tinytext,
`insert_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY `Índice 1` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `messages` (`id`, `message`, `insert_time`) VALUES
(1, 'm1', '2015-08-06 21:50:52'),
(2, 'm2', '2015-08-06 21:52:46');
CREATE TABLE IF NOT EXISTS `tweets` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`tweet` tinytext,
`created_by` int(11) DEFAULT NULL,
`insert_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
KEY `Índice 1` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=COMPACT;
INSERT INTO `tweets` (`id`, `tweet`, `created_by`, `insert_time`) VALUES
(1, 't1', 23, '2015-08-06 21:52:10'),
(2, 't2', 25, '2015-08-06 21:53:07');
Triggers:
DELIMITER //
CREATE TRIGGER `comments_before_insert` AFTER INSERT ON `comments` FOR EACH ROW BEGIN
insert into all_tables_order set insert_time = new.insert_time, id = new.id, table_name = 'comments';
END//
DELIMITER ;
CREATE TRIGGER `messages_after_insert` AFTER INSERT ON `messages` FOR EACH ROW BEGIN
insert into all_tables_order set insert_time = new.insert_time, id = new.id, table_name = 'messages';
END//
DELIMITER ;
DELIMITER //
CREATE TRIGGER `tweets_after_insert` AFTER INSERT ON `tweets` FOR EACH ROW BEGIN
insert into all_tables_order set insert_time = new.insert_time, id = new.id, table_name = 'tweets';
END//
DELIMITER ;
how can i count how many people in table a?
there 4 people exists in the below table , how can i get "4" in mysql?
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `a`
-- ----------------------------
DROP TABLE IF EXISTS `a`;
CREATE TABLE `a` (
`products_id` int(11) NOT NULL auto_increment,
`name` varchar(30) default NULL,
`date` datetime default NULL,
PRIMARY KEY (`products_id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of a
-- ----------------------------
INSERT INTO `a` VALUES ('1', 'jimmy', '2014-02-11 09:24:42');
INSERT INTO `a` VALUES ('7', 'khon', '2014-02-19 09:24:50');
INSERT INTO `a` VALUES ('3', 'jimmy', '2014-01-11 09:25:03');
INSERT INTO `a` VALUES ('4', 'kelvin', '2013-12-11 09:25:09');
INSERT INTO `a` VALUES ('5', 'ricky', '2014-02-12 09:25:14');
Use count on distinct name of the persons.
select count(distinct name) from a mytable
select count(distinct(name)) as count from a;
You can use COUNT LIke
SELECT COUNT(DISTINCT name) FROM a;
You are unclear in your question. What is it that you want to count?, number of distinct persons or the total number of people in the table?
SELECT COUNT(name) from a;
You may use DISTINCT clause with it or you can also perform GROUP BY to get the count of users by grouping them.
please see the the test data bellow. I want to get the avgtime (=timeonsite/visits) and display as "xx:xx:xx" result in mysql. how can I get it?
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `t`
-- ----------------------------
DROP TABLE IF EXISTS `t`;
CREATE TABLE `t` (
`id` int(11) NOT NULL auto_increment,
`timeOnsite` time default NULL,
`visits` int(11) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t
-- ----------------------------
INSERT INTO `t` VALUES ('1', '04:05:30', '20');
INSERT INTO `t` VALUES ('2', '03:00:00', '10');
INSERT INTO `t` VALUES ('3', '00:01:30', '17');
You can use TIME_TO_SEC function to change xx:xx:xx format to seconds.
SELECT TIME_TO_SEC('00:01:30') / 17; # return 5.2941
And then through SEC_TO_TIME you can convert seconds to time back as below :
SELECT SEC_TO_TIME(TIME_TO_SEC('00:01:30') / 17); # return 00:00:05
Are sure that you calculate avgtime in such way?
If yes, mysql select below:
select id, timeOnsite,visits, SEC_TO_TIME(TIME_TO_SEC(timeOnsite)/visits) as avgtime
from t