Displaying conditional mysql values in additional column - mysql

In a sample project i wanted to display data in such a way that based on dates the records for same student comes in additional columns.
mysql> desc sch_student;
+----------------+--------------+
| Field | Type |
+----------------+--------------+
| s_first_name | varchar(128) |
| s_last_name | varchar(128) |
| rollcode | int(8) |
| regnum | int(8) |
| in_time | datetime |
| out_time | datetime |
| total_time | int(8) |
+----------------+--------------+
for below query i am getting sample output like below , my expected output is something i am unable to get. I tried Sample join but it didn't work.
mysql> select * from sch_student;
+-------------------+---------------+--------------+-----------+---------------------+---------------------+----------------+
| s_first_name | s_last_name | rollcode | regnum | in_time | out_time | total_time |
+-------------------+---------------+--------------+-----------+---------------------+---------------------+----------------+
| Suzan | Matsuo | 8900 | 2897 | 2017-12-02 22:30:11 | 2017-12-02 22:30:11 | 00:17:00 |
| Scottie | Ogletree | 5624 | 5627 | 2017-12-02 16:40:01 | 2017-12-02 16:40:05 | 00:26:04 |
| Cynthia | Zimmerman | 3107 | 6348 | 2017-12-02 16:35:01 | 2017-12-02 16:35:01 | 00:59:89 |
| Ricardo | Shurtliff | 3072 | 261 | 2017-12-02 15:33:01 | 2017-12-02 15:33:01 | 00:16:55 |
| Elizabeth | Milligan | 4722 | 3233 | 2017-12-02 15:06:00 | 2017-12-02 15:10:33 | 00:14:33 |
+-------------------+---------------+--------------+-----------+---------------------+---------------------+----------------+
Expected output is something like below
+-------------------+---------------+--------------+-----------+---------------------+---------------------+----------------+--------------+-----------+---------------------+---------------------+----------------+
| s_first_name | s_last_name | Today's Meeting | Day Before Yesterday's Meeting |
| | rollcode | regnum | in_time | out_time | total_time | rollcode | regnum | in_time | out_time | total_time |
+-------------------+---------------+--------------+-----------+---------------------+---------------------+----------------+--------------+-----------+---------------------+---------------------+----------------+
| Suzan | Matsuo | 8900 | 2897 | 2017-12-02 22:30:11 | 2017-12-02 22:30:11 | 00:17:00 | 8900 | 2897 | 2017-11-30 12:30:11 | 2017-11-30 12:50:11 | 00:17:00 |
| Scottie | Ogletree | 5624 | 5627 | 2017-12-02 16:40:01 | 2017-12-02 16:40:05 | 00:26:04 | 5624 | 5627 | 2017-11-30 18:40:01 | 2017-11-30 19:33:05 | 00:26:04 |
| Cynthia | Zimmerman | 3107 | 6348 | 2017-12-02 16:35:01 | 2017-12-02 16:35:01 | 00:59:89 | 3107 | 6348 | 2017-11-30 13:35:01 | 2017-11-30 14:15:01 | 00:59:89 |
| Ricardo | Shurtliff | 3072 | 261 | 2017-12-02 15:33:01 | 2017-12-02 15:33:01 | 00:16:55 | 3072 | 261 | 2017-11-30 19:33:01 | 2017-11-30 20:33:01 | 00:16:55 |
| Elizabeth | Milligan | 4722 | 3233 | 2017-12-02 15:06:00 | 2017-12-02 15:10:33 | 00:14:33 | 4722 | 3233 | 2017-11-30 18:06:00 | 2017-11-30 19:10:33 | 00:14:33 |
+-------------------+---------------+--------------+-----------+---------------------+---------------------+----------------+--------------+-----------+---------------------+---------------------+----------------+
I tried below join and it's not returning expected output. Is it possible to display conditional column from table?
select * from
(
(select s_first_name,s_last_name,rollcode,regnum,in_time from sch_student where sch_student.in_time BETWEEN CURDATE()- INTERVAL 1 DAY AND CURDATE() ) As TD,
(select s_first_name,s_last_name,rollcode,regnum,in_time from sch_student where sch_student.in_time BETWEEN CURDATE()- INTERVAL 3 DAY AND CURDATE() ) As DBYS
) ;

I think this is what you need. I haven't tested it. Basically the query gets todays data LEFT joins to the day before yesterday's data. I assumed regnum and rollcode makes your primary key. Change if that isnt the case.
SELECT TD.* , DBYS.*
FROM (
SELECT s_first_name
,s_last_name
,rollcode
,regnum
,in_time
FROM sch_student
WHERE sch_student.in_time BETWEEN CURDATE() - INTERVAL 1 DAY
AND CURDATE()) AS TD
LEFT JOIN (
SELECT s_first_name
,s_last_name
,rollcode
,regnum
,in_time
FROM sch_student
WHERE sch_student.in_time BETWEEN CURDATE() - INTERVAL 3 DAY
AND CURDATE() - INTERVAL 2 DAY) AS DBYS
ON (TD.regnum = DBYS.regnum AND
TD.rollcode = DBYS.rollcode);

If you want to get info for today's meeting and the "day-before-yesterday's" meeting, try using a LEFT JOIN instead:
SELECT s_first_name, s_last_name, rollcode, regnum, in_time
FROM sch_student AS sch_today
LEFT JOIN sch_student AS sch_daybeforeyesterday ON
sch_today.<PK_FIELD> = sch_daybeforeyesterday.<PK_FIELD> AND
sch_daybeforeyesterday.in_time BETWEEN CURDATE()- INTERVAL 3 DAY AND CURDATE() - INTERVAL 2 DAY
WHERE sch_student.in_time BETWEEN CURDATE()- INTERVAL 1 DAY AND CURDATE()
This will give you all rows with "in_time" within the last 0-24 hours. For each of those rows, it will return any corresponding rows with "in_time" within the 48-72 hours.

Related

MySQL: Get all user's who have logged in before but not after certain date, not working as expected

I have following data and I have written a query to get all user's who have logged in before but not logged in after a given date:
+----+------------------+----------------------+
| id | user_login | date |
+----+------------------+----------------------+
| 1 | longtwin | 2018-03-29 22:15:56 |
| 2 | admin | 2018-03-29 22:16:05 |
| 3 | steve | 2018-06-29 22:19:45 |
| 4 | robinbiundo | 2017-03-29 22:56:13 |
| 5 | shannon | 2017-06-29 23:07:38 |
| 6 | long | 2017-04-29 23:40:58 |
| 7 | longtwin | 2017-04-29 23:41:57 |
| 8 | long | 2017-03-30 02:24:46 |
| 9 | long | 2017-03-30 03:11:48 |
| 10 | abigailrashbaum | 2016-03-30 11:50:43 |
| 11 | timothybrown | 2016-03-30 16:25:59 |
| 12 | timothybrown | 2016-03-30 17:09:27 |
| 13 | timothybrown | 2015-03-30 17:28:44 |
| 14 | timothybrown | 2015-03-30 17:33:06 |
| 15 | steve | 2014-03-30 18:03:46 |
| 16 | steve | 2014-03-30 18:04:48 |
| 17 | steve | 201-03-30 19:16:59 |
+----+------------------+----------------------+
I wrote following SQL but the result is not expected, please correct me what is wrong with my SQL?
SELECT p.user_login, COUNT(p.user_login)
FROM wp_login_log_backup p
WHERE p.user_login NOT IN (
SELECT u.user_login
FROM wp_login_log_backup u
WHERE u.date < '2017-04-07 00:00:00'
GROUP BY u.user_login
)
GROUP BY p.user_login;
I should get only timothybrown, robinbiundo as that user didn't login after 2017-04-07 00:00:00
You can use aggregation:
select user_login
from wp_login_log_backup llb
group by user_login
having max(date) < '2017-04-07';
You can select all users who logged in before a given date and then a NOT EXISTS query to determine those who have not also logged in since that date:
SELECT l1.user_login, COUNT(*) AS logins
FROM wp_login_log_backup l1
WHERE l1.date < '2017-04-07 00:00:00'
AND NOT EXISTS (SELECT *
FROM wp_login_log_backup l2
WHERE l2.user_login = l1.user_login
AND l2.date > '2017-04-07 00:00:00' )
GROUP BY l1.user_login
Output:
user_login logins
abigailrashbaum 1
robinbiundo 1
timothybrown 4
Demo on dbfiddle

joining two table not working as expected

I have been working on this for about two days now and cant seem to figure it out so I would love some help.
I have two tables:
mysql> select id, date, volume, symbol_id from control_quotedaily limit 5;
+-------+---- -------+----------+-----------+
| id | date | volume | symbol_id |
+-------+------------+----------+-----------+
| 13263 | 2017-11-02 | 7800191 | AXISBANK |
| 13264 | 2017-11-02 | 9303981 | SBIN |
| 13265 | 2017-11-02 | 8013536 | HDFCBANK |
| 13266 | 2017-11-03 | 9642624 | AXISBANK |
| 13267 | 2017-11-04 | 19642327 | AXISBANK |
+-------+------------+----------+-----------+
5 rows in set (0.00 sec)
14 rows in set (0.01 sec)
mysql> select * from control_oidaily
+-----------+------------+-------------+--------------+
| symbol_id | date | expiry_date | val_in_lakhs |
+-----------+------------+-------------+--------------+
| AXISBANK | 2017-11-02 | 2017-11-30 | 166881.8 |
| AXISBANK | 2017-11-02 | 2017-12-28 | 2676.84 |
| AXISBANK | 2017-11-02 | 2018-01-25 | 97.13 |
| HDFCBANK | 2017-11-02 | 2017-11-30 | 76351.11 |
| HDFCBANK | 2017-11-02 | 2017-12-28 | 1509.48 |
| HDFCBANK | 2017-11-02 | 2018-01-25 | 0 |
| SBIN | 2017-11-02 | 2017-11-30 | 88654.3 |
| SBIN | 2017-11-02 | 2017-12-28 | 1060.51 |
| SBIN | 2017-11-02 | 2018-01-25 | 0 |
| AXISBANK | 2017-11-03 | 2017-11-30 | 87640.06 |
+-----------+------------+-------------+--------------+
So for every quote in the control_quotedaily table this is what I want:
closest expiry_date for that quote from the control_oidaily table
I want the val_in_lakhs for that expiry_date.
Eg: For date 2017-11-02, the closest expiry is 2017-11-30 and I want the val_in_lakhs (76351.11) returned.
This is what I am trying:
select o.date, o.expiry_date as expiry_date, o.symbol_id, q.date, q.symbol_id, o.val_in_lakhs, q.tottrdval, q.volume, q.symbol_id
FROM control_oidaily o
JOIN ( select o.date, MIN(expiry_date) as expiry_date, symbol_id
FROM control_oidaily o
GROUP by o.date,o.symbol_id
ORDER BY o.date asc) as ed
ON ed.date = o.date
AND ed.symbol_id = o.symbol_id
AND ed.expiry_date = o.expiry_date
JOIN control_quotedaily q
ON q.date = ed.date
AND q.symbol_id = ed.symbol_id
This is the output I am expecting:
+-------+------------+----------+-----------+--------------+--------------+
| id | date | volume | symbol_id | expiry_date | val_in_lakhs |
+-------+------------+----------+-----------+--------------+--------------+
| 13263 | 2017-11-02 | 7800191 | AXISBANK | 2017-11-30 | 166881.8 |
| 13264 | 2017-11-02 | 9303981 | SBIN | 2017-11-30 | 88654.3 |
| 13265 | 2017-11-02 | 8013536 | HDFCBANK | 2017-11-30 | 76351.11 |
| 13266 | 2017-11-03 | 9642624 | AXISBANK | 2017-11-30 | 87640.06 |
+-------+------------+----------+-----------+--------------+--------------+
In a Derived Table, get the closest_expiry_date (minimum value of expiry_date), for a grouping of symbol_id and date, from control_oidaily table.
Join this with the control_quotedaily table on symbol_id and date, to get closest_expiry_date value for every row in the control_quotedaily table.
Now, use the same derived table again to join with control_oidaily table, matching up on date, expiry_date (with closest expiry date) and symbol_id to get val_in_lakhs.
You possibly want the following query:
SELECT q.id,
q.`date`,
q.volume,
q.symbol_id,
o1.expiry_date,
o1.val_in_lakhs
FROM control_quotedaily AS q
JOIN (SELECT o2.`date`,
o2.symbol_id
MIN(o2.expiry_date) as closest_expiry_date
FROM control_oidaily AS o2
GROUP by o2.`date`, o2.symbol_id
) AS dt
ON dt.`date` = q.`date`
AND dt.symbol_id = q.symbol_id
JOIN control_oidaily AS o1
ON dt.`date` = o1.`date`
AND dt.symbol_id = o1.symbol_id
AND dt.closest_expiry_date = o1.expiry_date

MySQL query to select min datetime grouped by 30 day intervals

Here's some dump data..
CREATE TABLE `customer` (
`approve_datetime` datetime DEFAULT NULL,
`created_date` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `customer` (`approve_datetime`, `created_date`)
VALUES
('2015-08-20 04:43:00','2015-08-20'),
(NULL,'2015-09-03'),
('2015-09-17 02:17:00','2015-09-17'),
(NULL,'2015-09-29'),
('2015-09-29 12:44:00','2015-09-29'),
('2015-10-08 03:09:00','2015-10-08'),
('2016-01-20 08:59:00','2016-01-19'),
('2016-05-03 09:38:00','2016-05-02'),
('2016-07-15 11:06:00','2016-07-15'),
(NULL,'2016-08-30'),
('2016-10-18 12:55:00','2016-10-18'),
(NULL,'2017-01-08'),
(NULL,'2017-02-02'),
('2017-02-13 02:58:00','2017-02-13');
Here is my current query which doesn't handle the 30 day groupings correctly.
SELECT a.*
FROM customer a
WHERE a.approve_datetime IN (
SELECT MIN(b.approve_datetime)
FROM customer b
WHERE b.created_date BETWEEN a.created_date
AND DATE_ADD(a.created_date, INTERVAL 30 DAY)
)
Which gives me the following.
+---------------------+--------------+
| approve_datetime | created_date |
+---------------------+--------------+
| 2015-08-20 04:43:00 | 2015-08-20 |
| 2015-09-17 02:17:00 | 2015-09-17 |
| 2015-09-29 12:44:00 | 2015-09-29 |
| 2015-10-08 03:09:00 | 2015-10-08 |
| 2016-01-20 08:59:00 | 2016-01-19 |
| 2016-05-03 09:38:00 | 2016-05-02 |
| 2016-07-15 11:06:00 | 2016-07-15 |
| 2016-10-18 12:55:00 | 2016-10-18 |
| 2017-02-13 02:58:00 | 2017-02-13 |
+---------------------+--------------+
Can the query be altered to achieve the following results?
+---------------------+--------------+
| approve_datetime | created_date |
+---------------------+--------------+
| 2015-08-20 04:43:00 | 2015-08-20 |
| 2015-09-29 12:44:00 | 2015-09-29 |
| 2016-01-20 08:59:00 | 2016-01-19 |
| 2016-05-03 09:38:00 | 2016-05-02 |
| 2016-07-15 11:06:00 | 2016-07-15 |
| 2016-10-18 12:55:00 | 2016-10-18 |
| 2017-02-13 02:58:00 | 2017-02-13 |
+---------------------+--------------+
Notice that records with created_date's 2015-09-17 and 2015-10-08 have been removed because they are within 30 days of the previous record which is the minimum date for that particular group. 2015-08-20 + 30 days starts off the first group with 2015-08-20 being the min date for that group.
I hope what I'm trying to achieve makes sense.
take a look at this. the result is different but look if this correct. Column 3 and 4 are only to see how it works.
SELECT
min(b.approve_datetime) AS approve_datetime
, min(b.created_date) AS created_date
, DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 AS dayd30
, FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 ) AS dayd30floorint
FROM customer b
GROUP BY FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 )
ORDER BY b.created_date ;
sample
MariaDB [testdb]> SELECT
-> min(b.approve_datetime) AS approve_datetime
-> , min(b.created_date) AS created_date
-> , DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 AS dayd30
-> , FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 ) AS dayd30floorint
-> FROM customer b
-> GROUP BY FLOOR( DATEDIFF(b.created_date,(SELECT min(created_date) FROM customer)) / 30 )
-> ORDER BY b.created_date ;
+---------------------+--------------+---------+----------------+
| approve_datetime | created_date | dayd30 | dayd30floorint |
+---------------------+--------------+---------+----------------+
| 2015-08-20 04:43:00 | 2015-08-20 | 0.0000 | 0 |
| 2015-09-29 12:44:00 | 2015-09-29 | 1.3333 | 1 |
| 2016-01-20 08:59:00 | 2016-01-19 | 5.0667 | 5 |
| 2016-05-03 09:38:00 | 2016-05-02 | 8.5333 | 8 |
| 2016-07-15 11:06:00 | 2016-07-15 | 11.0000 | 11 |
| NULL | 2016-08-30 | 12.5333 | 12 |
| 2016-10-18 12:55:00 | 2016-10-18 | 14.1667 | 14 |
| NULL | 2017-01-08 | 16.9000 | 16 |
| NULL | 2017-02-02 | 17.7333 | 17 |
| 2017-02-13 02:58:00 | 2017-02-13 | 18.1000 | 18 |
+---------------------+--------------+---------+----------------+
10 rows in set (0.00 sec)
MariaDB [testdb]>

How do I select the population of a User table as an increasing value by DATE?

Consider this excerpt of our Users table:
+-------------+---------------------+---------------------+
| id | last_login | created |
+-------------+---------------------+---------------------+
| 14551578822 | 2014-02-22 17:38:39 | 2013-03-26 23:30:50 |
| 18442388426 | 0000-00-00 00:00:00 | 2013-11-07 15:51:11 |
| 49983341634 | 2014-03-06 22:28:47 | 2013-03-23 16:00:05 |
| 9527246957 | 2014-01-17 02:37:53 | 2013-05-14 02:14:49 |
| 58667409337 | 2014-03-08 06:54:01 | 2013-05-15 01:52:23 |
| 1907780002 | 2014-03-01 03:24:04 | 2013-05-01 07:57:56 |
| 65319490251 | 2014-03-19 05:49:41 | 2013-03-23 08:53:43 |
| 23896465717 | 0000-00-00 00:00:00 | 2012-10-21 10:52:23 |
| 19147401900 | 0000-00-00 00:00:00 | 2013-05-01 17:43:28 |
| 28598429318 | 0000-00-00 00:00:00 | 2014-03-14 14:44:15 |
+-------------+---------------------+---------------------+
We have many, many users - and we would like to generate a report that will display the total number of users we have as the date increases. We would like output similar to this:
+---------+---------------+
| DATE | User Count |
+---------+---------------+
| 2012-08 | 122 |
| 2012-09 | 1746 |
| 2012-10 | 3847 |
| 2012-11 | 5826 |
...
| 2014-03 | 472647 |
| 2014-04 | 497286 |
+---------+---------------+
There must be some way to do it without subselects and all kinds of messiness like that. I have a table already that displays the number of joins per period by the following query:
SELECT DATE(users.created) as JOIN_DATE , COUNT(users.id) AS JOIN_COUNT from users
WHERE users.created > '2012-07-01 00:00:00'
GROUP BY JOIN_DATE
ORDER BY JOIN_DATE ASC
Just wondered if there was a way to do it something like that.
Thanks!
You can use a variable to sum up the population foreach iteration
SELECT t.date ,
#population := #population+t.per_time population
FROM (
SELECT
DATE_FORMAT(`last_login` ,'%Y-%m') `date`,
COUNT(*) per_time
FROM Table1
WHERE created > '2012-07-01 00:00:00'
GROUP BY `date` ) t ,
(SELECT #population:=0) p
Fiddle Demo

Specific query in Mysql

I have two tables reports and holidays.
reports: (username varchar(30),activity varchar(30),hours int(3),report_date date)
holidays: (holiday_name varchar(30), holiday_date date)
select * from reports gives
+----------+-----------+---------+------------+
| username | activity | hours | date |
+----------+-----------+---------+------------+
| prasoon | testing | 3 | 2009-01-01 |
| prasoon | coding | 4 | 2009-01-03 |
| prasoon | designing| 2 | 2009-01-04 |
| prasoon | coding | 4 | 2009-01-06 |
+----------+-----------+---------+------------+
select * from holidays gives
+--------------+---------------+
| holiday_name | holiday_date |
+--------------+---------------+
| Diwali | 2009-01-02 |
| Holi | 2009-01-05 |
+--------------+---------------+
Is there any way by which I can output the following?
+-------------+-----------+---------+-------------------+
| date | activity | hours | holiday_name |
+-------------+-----------+---------+-------------------+
| 2009-01-01 | testing | 3 | |
| 2009-01-02 | | | Diwali |
| 2009-01-03 | coding | 4 | |
| 2009-01-04 | designing| 2 | |
| 2009-01-05 | | | Holi |
| 2009-01-06 | coding | 4 | |
+-------------+-----------+---------+-------------------+
SELECT date,
activity,
hours,
'' AS holiday_name
FROM reports
WHERE date >= '2008-12-1'
AND date < '2009-1-4'
UNION
(SELECT holiday_date,
'',
'',
holiday_name
FROM holidays
WHERE holiday_date >= '2008-12-1'
AND holiday_date < '2009-1-4')
ORDER BY date
select * from
(select h.holdiday_date as date from holiday h
union
select r.date as date from reports r) dates
left join holiday h1 on (h1.holiday_date = dates.date)
left join reports r1 on (r1.date = dates.date)
order by dates.date
In short you union the dates you have in a subquery, than left join to the two tables.