My general question seems to be answered by https://stackoverflow.com/a/3025332/3650835, but I do not fully understand it after reading the MySql docs and am wondering if my solution will work as I expect, and also wonder if LIMIT 1 is needed.
Goal: to ensure that, for a given user_id, start and end never "overlap". As an example:
test_table
user_id start end
4 1 5
4 6 13
4 11 17 --> NOT allowed, bc 11 <= 13
2 1 9 --> allowed, user_id is different
My current solution
/* this should not insert anything, as it would cause an "overlap" of start
and end, based on row 2 having end = 13 */
INSERT INTO `test_table` (user_id, start, end)
SELECT '4', '11', '17' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `test_table`
WHERE user_id = '4' AND end >= '11')
LIMIT 1;
Does the WHERE NOT EXISTS section mean "only do this insert...if this following select returns nothing"?
Also, there was the following comment in the linked solution, but I do not understand why based on the MySql docs this would be true. If true, I could remove Limit 1 from my solution:
If you use "from dual" on line 2 instead of "from table", then you
don't need the "limit 1" clause
Thanks for your time.
Edit: here is all the sql for testing/setup:
CREATE TABLE `test_table`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`user_id` INT,
`start` INT,
`end` INT
);
INSERT INTO `test_table` (user_id, start, end)
SELECT '4', '1', '5' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `test_table`
WHERE user_id = '4' AND end >= '1')
LIMIT 1;
INSERT INTO `test_table` (user_id, start, end)
SELECT '2', '1', '9' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `test_table`
WHERE user_id = '2' AND end >= '1')
LIMIT 1;
INSERT INTO `test_table` (user_id, start, end)
SELECT '4', '6', '13' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `test_table`
WHERE user_id = '4' AND end >= '6')
LIMIT 1;
/* this should not insert anything, as it would cause an "overlap" of start and end */
INSERT INTO `test_table` (user_id, start, end)
SELECT '4', '11', '17' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `test_table`
WHERE user_id = '4' AND end >= '11')
LIMIT 1;
I'd use triggers instead:
-- This is your original table create statement
DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`user_id` INT,
`start` INT,
`end` INT
);
DELIMITER //
CREATE TRIGGER `TRG_test_table_before_insert` BEFORE INSERT ON `test_table` FOR EACH ROW BEGIN
SELECT
COUNT(*) INTO #cnt
FROM
test_table
WHERE
`user_id` = NEW.user_id
AND `start` <= NEW.`end`
AND `end` >= NEW.`start`
;
IF(#cnt > 0) THEN
SET #msg = CONCAT('TrgErr: overlapping, user_id = ', NEW.user_id, ', start = ', NEW.`start`, ', end = ', NEW.`end`);
SIGNAL SQLSTATE '45000' SET message_text = #msg;
END IF;
END//
DELIMITER ;
Then you will be able to use normal insert statements:
INSERT INTO `test_table` (user_id, `start`, `end`) VALUES ('4', '1', '5');
INSERT INTO `test_table` (user_id, `start`, `end`) VALUES ('2', '1', '9');
INSERT INTO `test_table` (user_id, `start`, `end`) VALUES ('4', '6', '13');
INSERT INTO `test_table` (user_id, `start`, `end`) VALUES ('4', '11', '17'); -- this one will not be inserted
In addition, you can implement the similar settings for updates.
P.S. You should check overlapping logic in my code as I do not know if start = end should be allowed or not.
P.P.S. Index (user_id, begin) will also help
NOT EXISTS means that get results for the inner query and if it returns any rows dont include that related row in the main query. But, your subquery does not have any relation with your main query, which makes me to think that the query may not be generating correct results.
select * from tbl1
where not exists (
select 1 from tbl2 where tbl1.id = tbl2.id
)
the above query makes lot more sense. It means that for every record in tbl1 check tbl2 and if any result is found dont include it in the query result.
It might be easier to understand what your query is doing if it is rewritten like this:
INSERT INTO `test_table` (user_id, start, end)
SELECT user_id, start, end
FROM ( SELECT 4 AS `user_id`, 6 AS `start`, 13 AS `end`) AS candidate
WHERE NOT EXISTS (
SELECT *
FROM `test_table` AS t
WHERE t.user_id = candidate.user_id AND t.end >= candidate.`end`
)
;
Also, note I removed the single quotes around the numbers; it may or may not be a problem in this case, but in some scenarios that could have resulted in some hard to find bugs where 2 > 11 (if MySQL decided to cast the t.end to a char type to compare with candidate.end).
A select from DUAL will only return ever return one row, so the LIMIT 1 is not required. However if you use your table name, your query will return either as many rows as are in the table, or none, dependent on whether the EXISTS expression returns true or false. So in that case you will need the LIMIT 1.
Your interpretation of what the WHERE NOT EXISTS does is correct.
If (start,end) pairs are only ever inserted in order, your existing test on end is sufficient. If however they might go backwards e.g. (4, 1, 2), (4, 5, 6), (4, 3, 4), then you should change your WHERE clause in the subquery to also test the start value, e.g. the last query should be written as
INSERT INTO `test_table` (user_id, start, end)
SELECT '4', '11', '17' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `test_table`
WHERE user_id = '4' AND
(start <= 11 AND end >= 11 OR start <= 17 AND end >= 17))
I made a small demo on dbfiddle to show how these work.
Related
I have the following query which works correctly:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT 10, 'user_other_unit_moved', now(), 8383
FROM Events
WHERE NOT EXISTS (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
LIMIT 1;
What the query does is check to see if a row exists in my Events table that matches the event type and unit ID I wish to INSERT. If it finds an existing record, it does not proceed with the INSERT. However, if it does not find a record then it proceeds with the INSERT.
This is the structure of my Events table:
CREATE TABLE `Events` (
`event_ID` int(11) NOT NULL,
`user_ID` int(11) NOT NULL,
`event_type` varchar(35) NOT NULL,
`event_creation_datetime` datetime NOT NULL,
`unit_ID` int(10) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `Events`
ADD PRIMARY KEY (`event_ID`),
ADD KEY `unit_ID` (`unit_ID`);
ALTER TABLE `Events`
MODIFY `event_ID` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
The problem I have is trying to get the above query to work correctly when trying to INSERT multiple rows. I know how to INSERT multiple rows using comma delimited VALUES, but no matter what I try I get syntax errors. Here is the query I have been playing with:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
VALUES (
(SELECT 10, 'user_other_unit_moved', now(), 8383
FROM Events
WHERE NOT EXISTS (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
LIMIT 1)),
(SELECT 10, 'user_other_unit_moved', now(), 8380
FROM Events
WHERE NOT EXISTS (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8380)
LIMIT 1))
);
However, no matter what I try (inserting, removing parentheses etc.) I get either the generic "You have an error in your SQL syntax;" or "Operand should contain only 1 column".
I have also tried this alternative based on other StackOverflow posts:
INSERT IGNORE INTO Events (event_ID, user_ID, event_type, event_creation_datetime, unit_ID)
VALUES
(SELECT (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383), 10, 'user_other_unit_moved', now(), 8383),
(SELECT (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383), 10, 'user_other_unit_moved', now(), 8383);
But this fails with "Can't specify target table for update in FROM clause" even if I try to return results using temporary tables.
Is it just an error with my syntax, or am I trying to do something not possible with the way my query is laid out? And if it's just an error, how would I write the query so that it works as I've intended? Note that I do not want to use multi-queries - I want the query to work as one statement.
Thanks,
Arj
Don't use VALUES, just INSERT ... SELECT and not FROM events.
Then UNION ALL.
This code works for MySql 5.6:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT *
FROM (
SELECT 10 user_ID, 'user_other_unit_moved' event_type,
now() event_creation_datetime, 8383 unit_ID
UNION ALL
SELECT 10, 'user_other_unit_moved', now(), 8380
) t
WHERE NOT EXISTS (
SELECT 1 FROM Events e
WHERE e.event_type = t.event_type AND e.unit_ID = t.unit_ID
);
See the demo.
This code works for MySql 5.7+:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT * FROM (
SELECT 10, 'user_other_unit_moved', now(), 8383
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
UNION ALL
SELECT 10, 'user_other_unit_moved', now(), 8380
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8380)
) t
See the demo
And this for MySql 8.0+:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT 10, 'user_other_unit_moved', now(), 8383
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
UNION ALL
SELECT 10, 'user_other_unit_moved', now(), 8380
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8380);
See the demo.
Although you can write this with just union all:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT x.user_id, x.event_type, now(), x.unit_id
FROM (SELECT 10 as user_id, 8383 as unit_id, 'user_other_unit_moved' as event_type
) x
WHERE NOT EXISTS (SELECT 1 FROM Events e2 WHERE e2.event_type = x.event_type AND e2.unit_ID = x.unit_ID)
UNION ALL
SELECT x.user_id, x.event_type, now(), x.unit_id
FROM (SELECT 10 as user_id, 8380 as unit_id, 'user_other_unit_moved' as event_type
) x
WHERE NOT EXISTS (SELECT 1 FROM Events e2 WHERE e2.event_type = x.event_type AND e2.unit_ID = x.unit_ID);
I suspect there is a better way. If a unit_id can have only one row for each event type, then you should specify that using a unique constraint or index:
create unique constraint unq_events_unit_id_event_type on events(unit_id, event_type);
It is better to have the database ensure integrity. In particularly, your version is subject to race conditions. And to duplicates being inserted within the same statement.
Then you can use on duplicate key to prevent duplicate rows:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
VALUES (10, 'user_other_unit_moved', now(), 8383),
(10, 'user_other_unit_moved', now(), 8380)
ON DUPLICATE KEY UPDATE unit_ID = VALUES(unit_ID);
The update actually does nothing (because unit_ID already has that value). But it does prevent an error and a duplicate row from being inserted.
I want to get the average number (Attendee NPS) from a SQL table I've already put together.
I've encased the initial table in a new select statement so I can take the average of distinct values. Is there something in my Join clause that is preventing this from working?
Im getting the following error:
ERROR: missing FROM-clause entry for table "gizmo" Position: 12
SELECT
avg(bigtable.gizmo.attendee_nps)
FROM
(
SELECT DISTINCT
attendee_survey_results.swoop_event_id AS "Swoop ID",
attendee_survey_results.startup_weekend_city AS "SW City",
swooptable.start_date AS "Date",
gizmo.attendee_nps AS "Attendee NPS"
FROM attendee_survey_results
JOIN
(
SELECT
swoop_event_id,
(
100 * count(CASE WHEN attendee_nps >= 9 THEN 1 END)
/ count(attendee_nps)
- 100 * count(CASE WHEN attendee_nps <= 6 THEN 1 END)
/ count(attendee_nps)
) AS "attendee_nps"
FROM attendee_survey_results
GROUP BY swoop_event_id
) AS "gizmo"
ON gizmo.swoop_event_id = attendee_survey_results.swoop_event_id
JOIN
(
SELECT eid,start_date,manager_email
FROM events
) AS "swooptable"
ON gizmo.swoop_event_id = swooptable.eid
) AS bigtable
[edit, ok you don't have a single problem, but the request at the bottom should work]
3 part notation bigtable.gizmo.attendee_nps
You can't use this bigtable.gizmo.attendee_nps, this is the "with DB" specific syntax : db_name.tbl_name.col_name.
You should use a table_or_alias.col_name_or_alias notation
In sub query you loose the deep table name of every deep-1 :
-- with the deep explicite
SELECT `d0`.`new_field`
FROM (
-- implicite `d1` table
SELECT `new_field`
FROM (
-- with the deep `d2` explicite and alias of field
SELECT `d2`.`field` AS `new_field`
FROM (
-- without the explicite `d3` table and `field` field
SELECT *
FROM (
-- output a `field` => 12
SELECT 12 as `field`
) AS `d3`
) AS `d2`
) AS `d1`
) AS `d0`
-- print `new_field` => 12
Access deep-1 aliased field
SELECT `attendee_nps`
FROM
(
SELECT `attendee_nps` AS `new_alias_field`
FROM attendee_survey_results
) AS bigtable
Unknown column 'attendee_nps' in 'field list'
When you make a field alias in deep-1 query, deep-0 can only access the alias new_alias_field, the original field no longer exist.
Double quote " table alias
FROM (
-- ...
) AS "bigtable"
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"bigtable"' at line N
MySql don't allow the use of " to make table alias (it's technically ok for field alias).
You should use the mysql back quote to escape table alias name, like AS `My Table Alias`
Correct query :
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE events
(`eid` int, `start_date` varchar(10), `manager_email` varchar(15))
;
INSERT INTO events
(`eid`, `start_date`, `manager_email`)
VALUES
(1, '2016-11-11', 'mail_1#mail.com'),
(2, '2016-11-12', 'mail_2#mail.com'),
(3, '2016-11-13', 'mail_3#mail.com'),
(4, '2016-11-14', 'mail_4#mail.com'),
(5, '2016-11-15', 'mail_5#mail.com'),
(6, '2016-11-16', 'mail_6#mail.com'),
(7, '2016-11-17', 'mail_7#mail.com')
;
CREATE TABLE attendee_survey_results
(`id` int, `swoop_event_id` int, `startup_weekend_city` varchar(6), `attendee_nps` int)
;
INSERT INTO attendee_survey_results
(`id`, `swoop_event_id`, `startup_weekend_city`, `attendee_nps`)
VALUES
(1, 1, 'city_1', 1),
(2, 2, 'city_2', 22),
(3, 3, 'city_3', 3),
(4, 1, 'city_4', 4),
(5, 2, 'city_5', 5),
(6, 3, 'city_6', 9),
(7, 7, 'city_7', 17)
;
Query 1:
SELECT
AVG(`bigtable`.`attendee_nps`)
FROM
(
SELECT DISTINCT
`asr`.`swoop_event_id` AS `Swoop ID`,
`asr`.`startup_weekend_city` AS `SW City`,
`swooptable`.`start_date` AS `date`,
`gizmo`.`attendee_nps` AS `attendee_nps`
FROM `attendee_survey_results` AS `asr`
JOIN
(
SELECT
`swoop_event_id`,
(
100 * count(CASE WHEN `attendee_nps` >= 9 THEN 1 END)
/ count(`attendee_nps`)
- 100 * count(CASE WHEN `attendee_nps` <= 6 THEN 1 END)
/ count(`attendee_nps`)
) AS `attendee_nps`
FROM `attendee_survey_results`
GROUP BY `swoop_event_id`
) AS `gizmo`
ON `gizmo`.`swoop_event_id` = `asr`.`swoop_event_id`
JOIN
(
SELECT `eid`, `start_date`, `manager_email`
FROM `events`
) AS `swooptable`
ON `gizmo`.`swoop_event_id` = `swooptable`.`eid`
) AS `bigtable`
Results:
| AVG(`bigtable`.`attendee_nps`) |
|--------------------------------|
| -14.28571429 |
I am trying to count the entries for the current day and sum the total. Currently, I have a query that counts the entries per day. I am using the datetime field to achieve my end goal. What would be the best approach to count the entries for the current day and sum the total?
CREATE TABLE product_entry
(`id` int, `entry_time` datetime, `product` varchar(55))
;
INSERT INTO product_entry
(`id`, `entry_time`, `product`)
VALUES
(1, '2015-09-03 15:16:52', 'dud1'),
(2, '2015-09-03 15:25:00', 'dud2'),
(3, '2015-09-04 16:00:12', 'dud3'),
(4, '2015-09-04 17:23:29', 'dud4')
;
SQLFIDDLE
Query
SELECT entry_time, count(*)
FROM product_entry
GROUP BY hour( entry_time ) , day( entry_time )
Schema
CREATE TABLE product_entry
(`id` int, `entry_time` datetime, `product` varchar(55))
;
INSERT INTO product_entry
(`id`, `entry_time`, `product`)
VALUES
(1, '2015-09-03 15:16:52', 'dud1'),
(2, '2015-09-03 15:25:00', 'dud2'),
(3, '2015-09-04 16:00:12', 'dud3'),
(4, '2015-09-04 17:23:29', 'dud4')
;
The title of your question says Count results for the current date ..., but the query you have tried suggests you want to show result counts for every distinct date. I am not sure which one you need. If the former is the case, you could simply use:
SELECT COUNT(`id`) FROM `product_entry` WHERE DATE(`entry_time`) = CURDATE()
To get count for today:
SELECT COUNT(`id`) FROM `product_entry` WHERE DATE(`entry_time`) = CURRENT_DATE
To get count for yesterday (needed when You want to get entries at end of the day):
SELECT COUNT(`id`) FROM `product_entry` WHERE DATE(`entry_time`) = SUBDATE(CURRENT_DATE, 1)
For all time grouped by date and formated:
SELECT DATE_FORMAT(entry_time,'%Y-%m-%d'), count(*)
FROM product_entry
GROUP BY date(entry_time)
this is MSSQL Code maybe your help
SELECT day([product_entry].[entry_time])as input, count(*) as Miktar
FROM [product_entry]
GROUP BY day([entry_time])
What I want to achieve is,
If the number of rows returned by the query:
SELECT count(*) FROM `games` WHERE cateID=2 AND active=1
is EQUAL to 0, I want to run an inserting query:
INSERT INTO games(cateID ,time,users,active)
VALUES ('2', '1', '0', '1')
I tried using case like this:
SELECT CASE WHEN SELECT count(*) FROM `games` WHERE cateID=2 AND active=1)=0
THEN INSERT INTO games(cateID ,time,users,active)
VALUES ('2', '1', '0', '1')
END
But it returns error as:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT count(*) FROM `games` WHERE cateID=2 AND active=1)=0
THEN INSERT INTO' at line 1
Note: Both queries when executed separately, execute without any error.
How do I achieve this ?
EDIT:
Also tried this with IF,
SELECT if(count(*)==0,INSERT INTO games(cateID ,time,users,active)
VALUES ('2', '1', '0', '1')) FROM `games` WHERE cateID=2 AND active=1
Still gives the same error.
EDIT 2:
By the suggested comment,
INSERT INTO games(cateID ,time,users,active)
select '2','2','0','1'
where (SELECT count(*) FROM `games` WHERE cateID=2 AND active=1) <= 0
Still gives error.
Try this
DECLARE
games_count INTEGER;
BEGIN
SELECT count(*) FROM `games` WHERE cateID=2 AND active=1 ;
IF games_count = 0 THEN
INSERT INTO games(cateID ,time,users,active) VALUES ('2', '1', '0', '1');
END IF;
END;
before to do the insert, check the select query. if the select query return 0 records nothing is inserting with the insert query.
select cateID,'2' as time,'0' as users,active
FROM
(select count(*) as countRecord,cateID,active
from games
where CATEID=2 and active=1 group by cateID,active) G
where countRecord <= 0
group by cateID, active,time,users
I want to find the time difference between two function names in my database. the database looks like this:
what I want to do is to find the time difference between two consecutive function names who have the same name. for example the output will be for "getPrice" at row number "2" and row number "3" and then time difference for "getPrice"at row "3" and row "5" and so on for all other times and all other function names. Please help me and thanks a lot!
I tried
SELECT a.lid, a.date, (b.date-a.date) as timeDifference
FROM myTable a
INNER JOIN myTable b ON b.lid = (a.lid+1)
ORDER BY a.lid ASC;
The problem is, it gives time difference for any consecutive function names even if they are not identical!
#tombom
there is a table I use for testing and have different variable names than the example I provided earlier. the table looks like this:
and after applying your code (and of course change the variable names to match with this table) the output looks like this:
as you can see the "getTax" is subtracted from "getPrice" although they are different. how can I solve this problem?? Thanks a lot.
the schema I'm trying to build is:
CREATE TABLE `test` (
`id` INT NOT NULL AUTO_INCREMENT ,
`nserviceName` VARCHAR(45) NULL ,
`functionName` VARCHAR(45) NULL ,
`time` TIMESTAMP NULL ,
`tps` INT NULL ,
`clientID` INT NULL ,
PRIMARY KEY (`id`) );
and the insert is :
INSERT INTO `test` (`id`, `nserviceName`, `functionName`, `time`, `tps`, `clientID`) VALUES ('1', 'X1', 'getPrice', '2013-05-23 00:36:08', '22', '0');
INSERT INTO `test` (`id`, `nserviceName`, `functionName`, `time`, `tps`, `clientID`) VALUES ('2', 'X2', 'getTax', '2013-05-23 00:38:00', '33', '0');
INSERT INTO `test` (`id`, `nserviceName`, `functionName`, `time`, `tps`, `clientID`) VALUES ('3', 'X1', 'getPrice', '2013-05-23 00:35:00', '12', '0');
INSERT INTO `test` (`id`, `nserviceName`, `functionName`, `time`, `tps`, `clientID`) VALUES ('4', 'X1', 'getPrice', '2013-05-23 00:35:00', '11', '0');
INSERT INTO `test` (`id`, `nserviceName`, `functionName`, `time`, `tps`, `clientID`) VALUES ('5', 'X2', 'getTax', '2013-05-23 00:35:00', '88', '0');
INSERT INTO `test` (`id`, `nserviceName`, `functionName`, `time`, `tps`, `clientID`) VALUES ('6', 'X1', 'getPrice', '2013-05-23 00:35:00', '33', '0');
thanks.
#tombom
the operation I want to perform on the table is like the following image:
where I start from the first record X1 getPrice which have no record before it. so no operation is required. then check number two getTax have no getPrice before it which are not identical so again no operation will be performed. then number 3 getPrice have getTax before it so it ignores it and check above getTax to find getPrice here it will do the time difference between getPrice(#3) and getPrice(#1). next getPrice at row 4 will check the rows above it, and it find the one directly above it is getPrice so time difference between getPrice*(#4) and getPrice(#3) will be found. then getTax at row 5 will check the rows above it until it finds a similar functionName (getTax) which is at row #2. then the time difference between getTax at row 5 and getTax at row 2 will be found.
thanks a lot..
Please have a try with this one:
SELECT lid, `date`, serviceName, functionName, responseTime, sid, timeDifference FROM (
SELECT
IF(#prevFname = functionName, SEC_TO_TIME(TIMESTAMPDIFF(SECOND, `date`, #prevDate)), 'functionName differs') AS timeDifference,
#prevFname := functionName AS a,
#prevDate := `date` AS b,
yt.*
FROM
yourTable yt
, (SELECT #prevFname:=NULL, #prevDate:=NULL) vars
ORDER BY functionName, `date`
) subquery_alias
I like to use user defined variables in such cases as I made amazing experiences regarding performance, since no self-join is needed.
Also note that I used the timestampdiff function and sec_to_time to polish the output. Timestampdiff is the correct way to subtract different dates(+times). Only downside is, that sec_to_time only allows a range from '00:00:00' to '23:59:59'. If this can lead to problems, remove the function again. Read more about both functions on this site.
UPDATE (less complicated than necessary):
SELECT lid, `date`, serviceName, functionName, responseTime, sid, timeDifference FROM (
SELECT
SEC_TO_TIME(TIMESTAMPDIFF(SECOND, #prevDate, `date`)) AS timeDifference,
#prevDate := `date` AS b,
yt.*
FROM
yourTable yt
, (SELECT #prevDate:=NULL) vars
ORDER BY lid
) subquery_alias
UPDATE 2:
This one resets the timedifference to 00:00:00 when functionName differs to previous one.
SELECT * /*choose here only the columns you need*/ FROM (
SELECT
IF(#prevFunction = functionName, SEC_TO_TIME(TIMESTAMPDIFF(SECOND, #prevDate, `time`)), '00:00:00') AS timeDifference,
#prevFunction := functionName AS a,
#prevDate := `time` AS b,
yt.*
FROM
test yt
, (SELECT #prevDate:=NULL, #prevFunction:=NULL) vars
ORDER BY id
) subquery_alias
UPDATE 3:
Okay, what a difficult birth. Just a minor tweak.
SELECT * /*choose here only the columns you need*/ FROM (
SELECT
IF(#prevFunction = functionName, SEC_TO_TIME(TIMESTAMPDIFF(SECOND, #prevDate, `time`)), '00:00:00') AS timeDifference,
#prevFunction := functionName AS a,
#prevDate := `time` AS b,
yt.*
FROM
test yt
, (SELECT #prevDate:=NULL, #prevFunction:=NULL) vars
ORDER BY functionName, id#, `time`
) subquery_alias
ORDER BY id
I order by function name and id again (or time if you prefer) in the subquery, do all the calculations, then sort it by id again in the outer query. That's it.