I have a table with the following setup:
CREATE TABLE IF NOT EXISTS `appointment` (
`appId` tinyint(3) UNSIGNED AUTO_INCREMENT NOT NULL,
`startDateTime` datetime,
`duration` time DEFAULT NULL
);
Sample Data:
appId startDateTime duration
1 2015-05-04 16:15:00 00:14:00
2 2015-05-12 08:15:00 05:54:00
3 2015-05-12 08:35:00 02:14:00
4 2016-05-04 08:11:00 04:11:00
5 2015-05-13 19:30:00 02:50:00
Expected Output:
appId startDateTime duration
2 2015-05-12 08:15:00 05:54:00
3 2015-05-12 08:35:00 02:14:00
I need a query that is able to check every entry in the table and return and entries that collide. In the sample data above, 2 and 3 will overlap. I can convert both of the fields to unix time and calculate the end time however I am not sure how to compare each entry
Any idea?
Using Faisal's fiddle...
-- ----------------------------
-- Table structure for appointment
-- ----------------------------
DROP TABLE IF EXISTS `appointment`;
CREATE TABLE `appointment` (
`appId` tinyint(10) NOT NULL AUTO_INCREMENT,
`startDateTime` datetime DEFAULT NULL,
`duration` time DEFAULT NULL,
PRIMARY KEY (`appId`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of appointment
-- ----------------------------
INSERT INTO `appointment` VALUES
('1', '2015-05-04 16:15:00', '00:14:00'),
('2', '2015-05-12 08:15:00', '05:54:00'),
('3', '2015-05-12 08:35:00', '02:14:00'),
('4', '2016-05-04 08:11:00', '04:11:00'),
('5', '2015-05-13 19:30:00', '02:50:00');
SELECT DISTINCT x.*
FROM appointment x
JOIN appointment y
ON y.startdatetime < x.startdatetime + INTERVAL TIME_TO_SEC(x.duration) SECOND
AND y.startdatetime + INTERVAL TIME_TO_SEC(y.duration) SECOND > x.startdatetime
AND y.appid <> x.appid;
appId startDateTime duration
3 12.05.2015 08:35:00 02:14:00
2 12.05.2015 08:15:00 05:54:00
http://rextester.com/YJA59081
Try with this below query. Hope it should be solve your problem.
SELECT
tbl1.*
FROM
appointment tbl1,
appointment tbl2
WHERE
tbl2.appId <> tbl1.appId
AND tbl2.startDateTime < tbl1.startDateTime + INTERVAL TIME_TO_SEC(tbl1.duration) SECOND
AND tbl2.startDateTime + INTERVAL TIME_TO_SEC(tbl2.duration) SECOND > tbl1.startDateTime;
By clicking on the below link you can see your expected result in live which you want.
SQL Fiddle Demo
Related
I have a database table with holiday requests in it. I now want to calculate, how many days the user has requested for a certain year. So far I did this:
Table:
CREATE TABLE `holidays` (
`id` int(11) NOT NULL,
`user` int(11) NOT NULL,
`begin` date NOT NULL,
`end` date NOT NULL,
`comment_user` text NOT NULL,
`entered_at` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Get all holidays in a year:
SELECT SUM((DATEDIFF(end, begin) + 1)) AS days
FROM holidays
WHERE user = :user AND begin LIKE '2021%'
But what can I do, if begin date is in the year before (e.g. 12/30/2020) or end date is in the next year (e.g. 01/05/2022), so the request extends over new year's eve.
EXAMPLE:
If I have a holiday request from 12/30/2020 to 01/02/2021, I wanna count just two days of that, not all four days.
Only the days in 2021
Is there any possibilty to limit the DATEDIFF calculation to 01/01/2021 AND 12/31/2021, but getting all requests affected in that year?
And how can I put that in one mysql-query? I can't find any solution on google for that.
Would be great, if someone had a similar problem and solved that.
Thank's in advance,
Tobias
I created a sample database like this (FIDDLE):
CREATE TABLE `holidays` (
`begin` date DEFAULT NULL,
`end` date DEFAULT NULL
)
INSERT INTO `holidays` VALUES
('2020-12-28','2021-01-05'),
('2020-12-05','2020-12-06'),
('2021-01-06','2021-01-06');
This SQL-statement:
select
begin,
CASE WHEN year(end)>year(begin) then ADDDATE(makedate(year(`end`),1),INTERVAL -1 DAY) else `end` end as END ,
year(begin) as year
from holidays
union all
select
makedate(year(`end`),1),
`end`,
year(`end`)
from holidays
where year(`begin`)<>year(`end`);
will have as output:
+------------+------------+------+
| begin | END | year |
+------------+------------+------+
| 2020-12-28 | 2020-12-31 | 2020 |
| 2020-12-05 | 2020-12-06 | 2020 |
| 2021-01-06 | 2021-01-06 | 2021 |
| 2021-01-01 | 2021-01-05 | 2021 |
+------------+------------+------+
BTW: One should never use, or at least try to avoid, reserved words in a table definition (like 'begin', 'end')
I have a database in SQL which contains information about students and books they are borrowing.
I have a table of loans which includes the book_id, the student_id, the day the book was taken and the number of days the book can be kept.
I want to auto-generate the return_date by adding the days at the date in which the book was taken. How can I do this using MySQL Workbench?
You can use MySQL datetime function date_add() to compute the target return_date. Assuming that the date when the book was loaned is called loan_date and that the duration is stored in loan_duration, expressed in days:
select
book_id,
student_id,
loan_date,
date_add(loan_date, interval loan_duration day) return_date
from loan_table
In an update statement:
update loan_table
set return_date = date_add(loan_date, interval loan_duration day)
where return_date is null -- only compute the return_dates that were not yet computed
Edit
If you want that value to be auto-generated, an option is to use a generated stored (or virtual) column (available since MySQL 5.7). This works by defining a computation rule, that MySQL will automatically apply when a record is inserted or updated.
Demo on DB Fiddle:
-- set up
create table loan_table(
id int primary key auto_increment,
book_id int,
student_id int,
loan_date date,
loan_duration int,
-- here is the generated column
return_date date
as (date_add(loan_date, interval loan_duration day)) stored
);
-- perform an insert
insert into loan_table(book_id, student_id, loan_date, loan_duration)
values(1, 1, '2019-11-02', 3)
-- check the computed value
select * from loan_table;
id | book_id | student_id | loan_date | loan_duration | return_date
-: | ------: | ---------: | :--------- | ------------: | :----------
1 | 1 | 1 | 2019-11-02 | 3 | 2019-11-05
You can use a combination of interval and + :
select book_id
, student_id
, date_taken
, number_od_days
, (date_taken + interval number_od_days day) as return_date
from loans;
Here is the example in the DEMO
If you want this column to be auto incremented I suggest you create a trigger in your table:
CREATE TRIGGER rentcheck
BEFORE INSERT ON loans
FOR EACH ROW
begin
if new.number_od_days < 0 or new.number_od_days is null then
signal sqlstate '45000';
else
set new.return_date = (new.date_taken + interval new.number_od_days day);
end if;
end;
With it you can control if the column number_of_days will be negative or not entered because that would result with non logical data. Here is the demo for the trigger: DEMO
you can use variables in mysql:
set #days = 10;
set #mydate := DATE_ADD("2019-11-01", INTERVAL #days DAY);
select #mydate;
and then use your insert statement:
Insert into Loan(... ,[return_date])
values (...., #mydate)
Hope it helps
I am having Table like given below
CREATE TABLE IF NOT EXISTS `testtab` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`auto_num` varchar(100) NOT NULL,
`seal_num` varchar(100) NOT NULL,
`arr_date` date NOT NULL,
`unload_date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
INSERT INTO `testtab` (`id`, `name`, `auto_num`, `seal_num`, `arr_date`, `unload_date`) VALUES
(1, 'contain1', 'AT0000004815', 'CN44178', '2014-11-28', '2014-11-28'),
(2, 'contain1', 'AT0000004815', 'CN44178', '2014-12-28', '2014-12-28'),
(3, 'contain1', 'AT0000004815', 'CN44178', '2014-12-28', '2014-11-28'),
(4, 'contain1', 'AT0000004815', 'CN44178', '2014-11-28', '2014-12-28'),
(5, 'contain2', 'AT0000000227', 'CG11818', '2015-09-12', '2015-08-30'),
(6, 'contain2', 'AT0000000227', 'CG11818', '2015-08-30', '2015-08-30'),
(7, 'contain2', 'AT0000000227', 'CG11818', '2015-09-12', '2015-09-14'),
(8, 'contain2', 'AT0000000227', 'CG11818', '2015-08-30', '2015-09-14'),
(9, 'contain3', 'AT0000005297', 'FG1005G', '2015-01-25', '2015-01-27'),
(10, 'contain3', 'AT0000005297', 'FG1005G', '2015-01-25', '2014-12-27');
I need output result like given below
Mysql query result must contain the max date values from arr_date, unload_date
Group by fields : name, auto_num, seal_num
id name auto_num seal_num arr_date unload_date
2 contain1 AT0000004815 CN44178 2014-12-28 2014-12-28
7 contain2 AT0000000227 CG11818 2015-09-12 2015-09-14
9 contain3 AT0000005297 FG1005G 2015-01-25 2015-01-27
What query i want to use here please help me anyone,
You can do this:
SELECT * FROM `testtab` t
WHERE (t.arr_date,t.unload_date) in(select max(arr_date),max(unload_date)
from `testtab` s where s.name = t.name
and s.auto_num = t.auto_num and s.seal_num = t.seal_num)
This will select the max arr_date and unload_date for each combination(name,auto_num,seal_num) and then check if both columns equal in the row, select it.
I guess you're seeking the latest arr_date and unload_date for each distinct combination of name, auto_num, and seal_num. But you have not explained your table's contents so I might be guessing wrong.
SQL Fiddle
This query gives you that. It does not give the row id, because it's possible the latest arr_date and the latest unload_date come from different rows.
select name, auto_num, seal_num,
MAX(arr_date) arr_date, MAX(unload_date) unload_date
from testtab
group by name, auto_num, seal_num
Results:
| name | auto_num | seal_num | arr_date | unload_date |
|----------|--------------|----------|-------------------|-------------------|
| contain1 | AT0000004815 | CN44178 | December, 28 2014| December, 28 2014|
| contain2 | AT0000000227 | CG11818 | September, 12 2015| September, 14 2015|
| contain3 | AT0000005297 | FG1005G | January, 25 2015| January, 27 2015|
From User Interface ,
user can select a date and click on the submit button ,
based on the input field how to display next 30 days records ??
This is my sqlfiddle
http://sqlfiddle.com/#!9/b1f3b/1
Currently i am using between as shown below
select * from historical_data
where current_day between '01-OCT-2015' and '07-OCT-2015'
Could you please let me know how can i write a query for this ??
Use proper datatypes. Use date and the likes of decimal. Not varchar for these.
Your code:
create table historical_data
(
current_day varchar(50) ,
open_value varchar(10)
);
INSERT INTO historical_data (current_day,open_value) values ('01-OCT-2015','23.50');
INSERT INTO historical_data (current_day,open_value) values ('03-OCT-2015','26.50');
INSERT INTO historical_data (current_day,open_value) values ('05-OCT-2015','21.50');
INSERT INTO historical_data (current_day,open_value) values ('03-Strawberries','33.44');
select * from historical_data
where current_day between '01-OCT-2015' and '07-OCT-2015'
yikes, you got Strawberries
Instead, do:
create table historical_data2
( id int auto_increment primary key,
current_day date not null ,
open_value decimal(10,2) not null
);
truncate table historical_data2;
INSERT INTO historical_data2 (current_day,open_value) values ('2015-09-01','11.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-10-01','23.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-10-03','26.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-10-04','21.50');
INSERT INTO historical_data2 (current_day,open_value) values ('03-Strawberries','33.44'); -- Error 1292: Incorrect date value
INSERT INTO historical_data2 (current_day,open_value) values ('2015-10-31','22.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-11-01','33321.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-11-02','4443321.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-11-03','55533321.50');
INSERT INTO historical_data2 (current_day,open_value) values ('2015-11-04','66633321.50');
Harness the power of built-in mysql's Date and Time Functions like add_add and interval functionality. These become available when you use proper data types. Plus math is performed properly, and they consume less space.
select * from historical_data2
where current_day between '2015-10-02' and DATE_ADD(date('2015-10-02'), INTERVAL 1 MONTH)
+----+-------------+------------+
| id | current_day | open_value |
+----+-------------+------------+
| 3 | 2015-10-03 | 26.50 |
| 4 | 2015-10-04 | 21.50 |
| 5 | 2015-10-31 | 22.50 |
| 6 | 2015-11-01 | 33321.50 |
| 7 | 2015-11-02 | 4443321.50 |
+----+-------------+------------+
The takeaway: use proper datatypes
I am using MySQL. I want to insert value's result from groupby of datetime to specific column (using where, maybe). Let say:
I have two tables (a, b). In table a, I want to get how many total records during a hour (which I have datetime column), then the result will insert into table b, but in specific ID (there is already exist ID's value).
This is my error code:
INSERT INTO b(value)
WHERE ID=15
SELECT DAY COUNT(*)
FROM a
WHERE date >= '2015-09-19 00:00:00' AND date < '2015-09-19 00:59:59'
GROUP BY DAY(date),HOUR(date);";
Is that possible I make a query from this case?
Thank you very much for any reply!
Schema
create table tA
( id int auto_increment primary key,
theDate datetime not null,
-- other stuff
key(theDate) -- make it snappy fast
);
create table tB
( myId int primary key, -- by definition PK is not null
someCol int not null
);
-- truncate table tA;
-- truncate table tB;
insert tA(theDate) values
('2015-09-19'),
('2015-09-19 00:24:21'),
('2015-09-19 07:24:21'),
('2015-09-20 00:00:00');
insert tB(myId,someCol) values (15,-1); -- (-1) just for the heck of it
insert tB(myId,someCol) values (16,-1); -- (-1) just for the heck of it
The Query
update tB
set someCol=(select count(*) from tA where theDate between '2015-09-19 00:00:00' and '2015-09-19 00:59:59')
where tB.myId=15;
The Results
select * from tB;
+------+---------+
| myId | someCol |
+------+---------+
| 15 | 2 |
| 16 | -1 |
+------+---------+
only myId=15 is touched.