inserting date formatted with date_format(str_to_date())) - mysql

I'm putting all 2018 sundays into a table. I got the list and have to reformat it to fit into a datetime column.
This query generates a result
select date_format(str_to_date("February 11 2018","%M %d %Y"),"%Y-%m-%d %I:%i");
so, I thought I could just put that in an insert
INSERT INTO `events` (`id`, `title`, `color`, `start`, `end`)
VALUES (NULL, 'Sunday', '#FFE761',
(select date_format(str_to_date("January 14 2018","%M %d %Y"),"%Y-%m-%d %I:%i")),
'0000-00-00 00:00:00';
But, I'm getting errors regardless of how I try to stick the date in. I've tried removing 'select', the parens, the %I:%i.. I'm stuck.
Can you help?

INSERT INTO `events` (`id`, `title`, `color`, `start`, `end`)
VALUES (NULL, 'Sunday', '#FFE761',
(select date_format(str_to_date("January 14 2018","%M %d %Y"),"%Y-%m-%d %I:%i"),
'0000-00-00 00:00:00';

You have too many closing brackets after the format for the date.
INSERT INTO `events` (`id`, `title`, `color`, `start`, `end`)
VALUES (NULL, 'Sunday', '#FFE761',
(select date_format(str_to_date("January 14 2018","%M %d %Y"),"%Y-%m-%d %I:%i")), '0000-00-00 00:00:00')

Related

How to get difference or delta of counts entries of each days with window functions?

I have a table with few fields like id, country, ip, created_at. Then I am trying to get the deltas between total entry of one day and total entry of the next day.
CREATE TABLE session (
id int NOT NULL AUTO_INCREMENT,
country varchar(50) NOT NULL,
ip varchar(255),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
INSERT INTO `session` (`id`, `country`, `ip`, `created_at`) VALUES
('1', 'IN', '10.100.102.11', '2021-04-05 20:26:02'),
('2', 'IN', '10.100.102.11', '2021-04-05 19:26:02'),
('3', 'US', '10.120.102.11', '2021-04-17 10:26:02'),
('4', 'US', '10.100.112.11', '2021-04-16 12:26:02'),
('5', 'AU', '10.100.102.122', '2021-04-12 19:36:02'),
('6', 'AU', '10.100.102.122', '2021-04-12 18:20:02'),
('7', 'AU', '10.100.102.122', '2021-04-12 23:26:02'),
('8', 'US', '10.100.102.2', '2021-04-16 21:33:01'),
('9', 'AU', '10.100.102.122', '2021-04-18 20:46:02'),
('10', 'AU', '10.100.102.111', '2021-04-04 13:19:12'),
('11', 'US', '10.100.112.11', '2021-04-16 12:26:02'),
('12', 'IN', '10.100.102.11', '2021-04-05 15:26:02'),
('13', 'IN', '10.100.102.11', '2021-04-05 19:26:02');
Now I have written this query to get the delta
SELECT T1.date1 as date, IFNULL(T1.cnt1-T2.cnt2, T1.cnt1) as delta from (
select TA.dateA as date1, MAX(TA.countA) as cnt1 from (
select DATE(created_at) AS dateA, COUNT(*) AS countA
FROM session
GROUP BY DATE(created_at)
UNION
select DISTINCT DATE(DATE(created_at)+1) AS dateA, 0 AS countA
FROM session
) as TA
group by TA.dateA
) as T1
LEFT OUTER JOIN (
select DATE(DATE(created_at)+1) AS date2,
COUNT(*) AS cnt2
FROM session
GROUP BY DATE(created_at)
) as T2
ON T1.date1=T2.date2
ORDER BY date;
http://sqlfiddle.com/#!9/4f5fd26/60
Then I am getting the results as
date delta
2021-04-04 1
2021-04-05 3
2021-04-06 -4
2021-04-12 3
2021-04-13 -3
2021-04-16 3
2021-04-17 -2
2021-04-18 0
2021-04-19 -1
Now, is there any place of improvements/optimizes on it with/or window functions? (I am zero with SQL, still playing around).
Try a shorter version
with grp as (
SELECT t.dateA, SUM(t.cnt) AS countA
FROM session,
LATERAL (
select DATE(created_at) AS dateA, 1 as cnt
union all
select DATE(DATE(created_at)+1), 0 as cnt
) t
GROUP BY dateA
)
select t1.dateA as date, IFNULL(t1.countA-t2.countA, t1.countA) as delta
from grp t1
left join grp t2 on DATE(t2.dateA + 1) = t1.dateA
order by t1.dateA
db<>fiddle

Query to display row after 1 pm

How to fetch all rows from table where time is greater than 13:00 i.e. 1PM
SELECT * FROM `mytable` WHERE `time` >="13:00";
if you have a datetime field you could do this (I'm assuming here as you haven't specified):
create table tester(`id` int(6), `name` varchar(50), `datetest` datetime);
insert into tester(`id`,`name`,`datetest`)
values(1, 'n1', '2018-12-20 09:00:00'),
(2, 'n2', '2018-12-20 10:00:00'),
(3, 'n3', '2018-12-20 13:10:00'),
(4, 'n4', '2018-12-20 14:00:00');
select * from tester
where TIME(datetest) > '13:00'

SQL getting shifts outside of availability

I'm trying to put together an sql query to get employee shifts that are outside of their availability for a scheduling app. Availability entries will be contiguous and will never have availability entries that are back-to-back for the same employee, nor will there be availability entries that overlap for the same employee.
Basically, I need to get the shift rows where (availabilities.start <= shifts.start AND availabilities.end >= shifts.end) does NOT hold true. Phrased another way, I need to get the rows from the shifts table that are not fully contained by an availability entry.
It needs to account for these possibilities:
Shifts that start before availability
Shifts that end after availability
Shifts that do not have any availability during the shift
I'm ok with using a stored procedure instead of a query if this would be more efficient.
Here's what the tables look like:
CREATE TABLE availabilities (`id` int primary key, `employee_id` int, `start` datetime, `end` datetime);
CREATE TABLE shifts (`id` int primary key, `employee_id` int, `start` datetime, `end` datetime);
Here is some sample data:
INSERT INTO availabilities
(`employee_id`, `start`, `end`)
VALUES
(1, '2015-01-01 08:00:00', '2015-01-01 09:00:00'),
(1, '2015-01-02 08:00:00', '2015-01-02 10:00:00'),
(2, '2015-01-03 08:00:00', '2015-01-03 14:00:00'),
(2, '2015-01-04 08:00:00', '2015-01-04 18:00:00')
;
INSERT INTO shifts
(`employee_id`, `start`, `end`)
VALUES
(1, '2015-01-01 08:00:00', '2015-01-01 09:00:00'),
(1, '2015-01-02 08:30:00', '2015-01-02 10:00:00'),
(1, '2015-01-02 10:30:00', '2015-01-02 12:00:00'),
(2, '2015-01-03 08:00:00', '2015-01-03 09:00:00'),
(2, '2015-01-03 09:00:00', '2015-01-03 14:30:00'),
(2, '2015-01-04 09:30:00', '2015-01-04 17:30:00'),
(2, '2015-01-05 08:00:00', '2015-01-05 10:00:00')
;
I would expect the 3rd, 5th and 7th shifts to be output as they are outside of availability.
I've tried something like the following (as well as many others) however all of them either give false positives or leave out shifts.
SELECT s.* FROM `shifts` AS `s`
LEFT JOIN `availabilities` AS `a` ON `s`.`employee_id` = `a`.`employee_id`
WHERE (NOT(a.start <= s.start AND a.end >= s.end) OR a.id IS NULL);
Does this help?
select *
from shifts as s
where not exists (
select 1
from availabilities as a
where a.start <= s.start AND a.end >= s.end and a.employee_id = s.employee_id
)

MySQL query to show running total per week

I have a table where a close date will be updated upon close...until that time the field is null. I need to show a close trend grouped every 7 days from the start. So for example if there are 10 rows and 2 were closed in the first week then the total for that week should be 8. I have been able to create a query that works to show how many were closed in each week but I am struggling to find a way to account for the previous weeks totals.
Table
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `test_data`;
CREATE TABLE `test_data` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`close_date` date DEFAULT NULL,
`location` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
INSERT INTO `test_data` VALUES ('1', '2015-02-02', 'one');
INSERT INTO `test_data` VALUES ('2', '2015-02-02', 'one');
INSERT INTO `test_data` VALUES ('3', '2015-02-09', 'one');
INSERT INTO `test_data` VALUES ('4', '2015-02-09', 'one');
INSERT INTO `test_data` VALUES ('5', '2015-02-09', 'one');
INSERT INTO `test_data` VALUES ('6', '2015-02-16', 'one');
INSERT INTO `test_data` VALUES ('7', '2015-02-16', 'one');
INSERT INTO `test_data` VALUES ('8', '2015-02-16', 'one');
INSERT INTO `test_data` VALUES ('9', '2015-02-16', 'one');
INSERT INTO `test_data` VALUES ('10', '2015-02-16', 'one');
INSERT INTO `test_data` VALUES ('11', '2015-02-02', 'two');
INSERT INTO `test_data` VALUES ('12', '2015-02-02', 'two');
INSERT INTO `test_data` VALUES ('13', '2015-02-09', 'two');
INSERT INTO `test_data` VALUES ('14', '2015-02-09', 'two');
INSERT INTO `test_data` VALUES ('15', '2015-02-09', 'two');
INSERT INTO `test_data` VALUES ('16', '2015-02-16', 'two');
INSERT INTO `test_data` VALUES ('17', '2015-02-16', 'two');
INSERT INTO `test_data` VALUES ('18', '2015-02-16', 'two');
INSERT INTO `test_data` VALUES ('19', '2015-02-16', 'two');
INSERT INTO `test_data` VALUES ('20', '2015-02-16', 'two');
Query so far
select
'2015-02-02' + INTERVAL (DATEDIFF(test_data.close_date, '2015-02-02') DIV 7) WEEK as start_week,
(SELECT COUNT(*) FROM test_data WHERE location = 'one') - COUNT(a.id) AS one,
(SELECT COUNT(*) FROM test_data WHERE location = 'two') - COUNT(b.id) AS two
from test_data
left join test_data as a on a.id = test_data.id and a.location = 'one'
left join test_data as b on b.id = test_data.id and b.location = 'two'
where test_data.close_date >= '2015-02-02'
group by DATEDIFF(test_data.close_date,'2015-02-02') DIV 7
Output
start_week one two
2015-02-02 8 8
2015-02-09 7 7
2015-02-16 5 5
Output I am trying to achieve
start_week one two
2015-02-02 8 8
2015-02-09 5 5
2015-02-16 0 0
A push in the right direction is appreciated as I continue to work on this.
EDIT: More explanation of expected results.
As you can see in "Output" it is calculating the number of closed subtracted from the total. For location "one" there are 10 entries and in week 1 there were 2 closed (so 8 were still open in week 1), in week 2 3 more were closed giving the total closed since the beginning as 5 to the total in week 2 should be 5 instead.
So for my desired output.
start_week one
2015-02-02 8 <-- Total 10 - 2 closed in this week = 8
2015-02-09 5 <-- Total 10 - (3 closed in this week + the 2 in week 1) = 5
2015-02-16 0 <-- Total 10 - (5 closed in this week + the previous weeks) = 0
Columns a1 and a2 are the answers you are looking for. I tried this without the derived table did not get the correct answer. There is either a mysql bug or a misunderstanding on my part. But with the derived table it seems to work fine.
SELECT
sums.start_week,sums.*,
sums.tot1-sums.cur1-sums.back1 a1,sums.tot2-sums.cur1-sums.back2 a2
FROM
( /* Derived table cf counts */
SELECT DATEDIFF(test_data.close_date,'2015-02-02') DIV 7 AS sd,
'2015-02-02' + INTERVAL (DATEDIFF(test_data.close_date, '2015-02-02') DIV 7) WEEK as start_week,
(select COUNT(*) from test_data d1 where d1.location='one') tot1,
(select COUNT(*) from test_data d2 where d2.location='two') tot2,
count(CASE WHEN test_data.location='one' then 1 else null end ) cur1,
count(CASE WHEN test_data.location='two' then 1 else null end
) cur2,
(select count(*) from test_data d1 where d1.location='one' AND d1.close_date<
('2015-02-02' + INTERVAL (DATEDIFF(test_data.close_date, '2015-02-02') DIV 7) WEEK) ) as back1,
(select count(*) from test_data d2 where d2.location='two' AND d2.close_date<
('2015-02-02' + INTERVAL (DATEDIFF(test_data.close_date, '2015-02-02') DIV 7) WEEK) ) as back2
from test_data
where test_data.close_date >= '2015-02-02'
group by DATEDIFF(test_data.close_date,'2015-02-02') DIV 7 ,
'2015-02-02' + INTERVAL (DATEDIFF(test_data.close_date, '2015-02-02') DIV 7) WEEK
) sums

MySQL `HAVING` issue

I have two queries which are returning different results when I would expect them to return the same results.
The first query returns the correct result.
The second returns a result, but it is incorrect.
Why is this and how can I fix the second statement so that it returns the same result? I have to use the HAVING clause in this statement.
1.
SELECT
CAST(CONCAT(DATE(`mytable`.`starttime`),' ',HOUR(`mytable`.`starttime`),':',LPAD(60*(MINUTE(`mytable`.`starttime`) DIV 60),2,'0'),':00') AS DATETIME) AS `date`,
`mytable`.`id`
FROM
`mytable`
WHERE
`mytable`.`starttime`>='2011-07-01 00:00:00'
AND `mytable`.`starttime`<='2011-07-01 23:59:59'
AND `id` BETWEEN 1 AND 100
GROUP BY
`mytable`.`id`
2.
SELECT
CAST(CONCAT(DATE(`mytable`.`starttime`),' ',HOUR(`mytable`.`starttime`),':',LPAD(60*(MINUTE(`mytable`.`starttime`) DIV 60),2,'0'),':00') AS DATETIME) AS `date`,
`mytable`.`id`
FROM
`mytable`
WHERE
`id` BETWEEN 1 AND 100
GROUP BY
`mytable`.`id`
HAVING `date` IN ('2011-07-01 00:00:00', '2011-07-01 01:00:00', '2011-07-01 02:00:00', '2011-07-01 03:00:00', '2011-07-01 04:00:00', '2011-07-01 05:00:00', '2011-07-01 06:00:00', '2011-07-01 07:00:00', '2011-07-01 08:00:00', '2011-07-01 09:00:00', '2011-07-01 10:00:00', '2011-07-01 11:00:00', '2011-07-01 12:00:00', '2011-07-01 13:00:00', '2011-07-01 14:00:00', '2011-07-01 15:00:00', '2011-07-01 16:00:00', '2011-07-01 17:00:00', '2011-07-01 18:00:00', '2011-07-01 19:00:00', '2011-07-01 20:00:00', '2011-07-01 21:00:00', '2011-07-01 22:00:00', '2011-07-01 23:00:00')
Thanks in advance for any help you can offer.
WHERE clause is applied before GROUPing while HAVING is applied after. So in your second query where you have GROUP BY with no WHERE clause MySql returns a random (undetermined) single row and then applies the HAVING clause to it.
Group by is used with aggregate functions - sum, min, max, count. Your query doesn't appear to have an aggregate in the "select" - so group by doesn't do anything.
Whilst your query may be valid SQL, it doesn't make sense. Not sure if this is why your having clause is going nuts, though.
I assume "id" is a primary key on your table, is that right? I'm guessing that you want to show the times during the day at which various events occurred but I'm not sure why you would group by id then. Could you give an example of how you would like the output to look?