microsoft sql server datediff for multiple dates - sql-server-2008

I need to find the length of time between 2 dates (datetime types) based on the unique ID. For example, I have the following data:
ID CallID Starttime
1 56 2011-01-04 10:00:00.000
1 67 2011-03-20 12:20:00.000
1 70 2011-04-08 15:00:00.000
2 57 2011-01-14 11:00:00.000
2 62 2011-02-14 11:00:00.000
2 64 2011-02-15 11:00:00.000
2 75 2011-04-14 11:00:00.000
2 78 2011-05-14 11:00:00.000
I need to find the length of time for all the CallIDs for each ID based on the previous call date (starttime). For example, I need the length of time for all the calls for ID 1 (CallID 67 - CallID 56 and CallID 70 - CallID 67, etc.).
I know I need a loop of some kind that would go through the IDs to find the CallIDs for that ID but do I also need a temporary table where I would organize the CallIDs?
Any suggestions would be appreciated. Thank you.

One way.
;WITH T
AS (SELECT ID,
CallID,
Starttime,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Starttime) RN
FROM YourTable)
SELECT t1.ID,
t1.CallID,
t2.CallID,
DATEDIFF(HOUR, t1.Starttime, t2.Starttime)
FROM T t1
INNER JOIN T t2
ON t1.RN = t2.RN - 1
AND t1.ID = t2.ID

Related

SQL subquery in SELECT clause

I'm trying to find admin activity within the last 30 days.
The accounts table stores the user data (username, password, etc.)
At the end of each day, if a user had logged in, it will create a new entry in the player_history table with their updated data. This is so we can track progress over time.
accounts table:
id
username
admin
1
Michael
4
2
Steve
3
3
Louise
3
4
Joe
0
5
Amy
1
player_history table:
id
user_id
created_at
playtime
0
1
2021-04-03
10
1
2
2021-04-04
10
2
3
2021-04-05
15
3
4
2021-04-10
20
4
5
2021-04-11
20
5
1
2021-05-12
40
6
2
2021-05-13
55
7
3
2021-05-17
65
8
4
2021-05-19
75
9
5
2021-05-23
30
10
1
2021-06-01
60
11
2
2021-06-02
65
12
3
2021-06-02
67
13
4
2021-06-03
90
The following query
SELECT a.`username`, SEC_TO_TIME((MAX(h.`playtime`) - MIN(h.`playtime`))*60) as 'time' FROM `player_history` h, `accounts` a WHERE h.`created_at` > '2021-05-06' AND h.`user_id` = a.`id` AND a.`admin` > 0 GROUP BY h.`user_id`
Outputs this table:
Note that this is just admin activity, so Joe is not included in this data.
from 2021-05-06 to present (yy-mm-dd):
username
time
Michael
00:20:00
Steve
00:10:00
Louise
00:02:00
Amy
00:00:00
As you can see this from data, Amy's time is shown as 0 although she has played for 10 minutes in the last month. This is because she only has 1 entry starting from 2021-05-06 so there is no data to compare to. It is 0 because 10-10 = 0.
Another flaw is that it doesn't include all activity in the last month, basically only subtracts the highest value from the lowest.
So I tried fixing this by comparing the highest value after 2021-05-06 to their most previous login before the date. So I modified the query a bit:
SELECT a.`Username`, SEC_TO_TIME((MAX(h.`playtime`) - (SELECT MAX(`playtime`) FROM `player_history` WHERE a.`id` = `user_id` AND `created_at` < '2021-05-06'))*60) as 'Time' FROM `player_history` h, `accounts` a WHERE h.`created_at` >= '2021-05-06' AND h.`user_id` = a.`id` AND a.`admin` > 0 GROUP BY h.`user_id`
So now it will output:
username
time
Michael
00:50:00
Steve
00:50:00
Louise
00:52:00
Amy
00:10:00
But I feel like this whole query is quite inefficient. Is there a better way to do this?
I think you want lag():
SELECT a.username,
SEC_TO_TIME(SUM(h.playtime - COALESCE(h.prev_playtime, 0))) as time
FROM accounts a JOIN
(SELECT h.*,
LAG(playtime) OVER (PARTITION BY u.user_id ORDER BY h.created_at) as prev_playtime
FROM player_history h
) h
ON h.user_id = a.id
WHERE h.created_at > '2021-05-06' AND
a.admin > 0
GROUP BY a.username;
In addition to the LAG() logic, note the other changes to the query:
The use of proper, explicit, standard, readable JOIN syntax.
The use of consistent columns for the SELECT and GROUP BY.
The removal of single quotes around the column alias.
The removal of backticks; they just clutter the query, making it harder to write and to read.

MySQL last 50 records

I have to get the last 50 records from my MySQL database.
Here is the structure of my test database:
ID S1 S2 S3 Date-time Label
13 32 55 33 2017-09-05 13:15:06 temperature
16 111 222 66 2017-09-05 19:22:14 temperature
17 44 55 33 2017-09-05 19:22:14 temperature
18 55 11 88 2017-09-12 14:22:00 temperature
21 77 1 200 2017-09-15 12:24:06 temperature
22 22 55 11 2017-09-19 14:37:00 temperature
How could I show only the last 3 data? for example:
18 55 11 88 2017-09-12 14:22:00 temperature
21 77 1 200 2017-09-15 12:24:06 temperature
22 22 55 11 2017-09-19 14:37:00 temperature
Greetings and thank you.
In Oracle12c you can use the fetch keywork:
SELECT *
FROM table
ORDER BY id DESC
FETCH FIRST 50 ROWS ONLY;
FOR ORACLE:
SELECT * FROM (
SELECT ID,
S1,
S2,
S3,
Date-time,
Label
FROM TABLE
ORDER BY ID DESC)
WHERE ROWNUM <= 50;
FOR MYSQL:
SELECT ID,
S1,
S2,
S3,
Date-time,
Label
FROM TABLE
ORDER BY ID DESC
LIMIT 50;
Here is a quick doc:
https://www.w3schools.com/sql/sql_top.asp
Edit:
For the last 50 rows:
SELECT * FROM (
SELECT * FROM table ORDER BY id DESC LIMIT 50
) sub
ORDER BY id ASC
Use Top N Query (row num<=50) fro first, for last 50 you can use "order by id desc"
First I was confused with the Post between ORACLE and MYSQL I apologize.
The solution at the end was the following:
SELECT * FROM inv ORDER BY id DESC LIMIT 50
then transform the ARRAY that I collect with the function:
var dorde = d0.reverse ();
thanks for everything.

How to group data per week in MySQL?

id modid userid timemodified FROM_UNIXTIME(timemodified,'%d-%m-%Y')
410 32 46 1438971403 03-08-2015
411 32 46 1438971403 03-08-2015
412 66 977 1438971403 07-08-2015
412 66 977 1438971403 07-08-2015
413 67 34 1438971423 07-08-2015
414 68 16 1438971424 07-08-2015
415 132 23 1438972154 07-08-2015
416 134 2 1438972465 08-08-2015
417 115 2 1438996430 08-08-2015
418 130 977 1438996869 08-08-2015
I got this query from framing the last 4weeks ago by calculating from today's date. Now, I want to show the users for 4 weeks individually like week1, week2, week3 & week4, either it could be column wise or row wise, which would be the best.
In detailed, from the above query, I need to separate data from week1 to week4,like
Week4 : No user
Week3 : 2 users (2,977)
Week2 : 4 users (16, 23, 34, 977)
Week1 : 1 user (46)
SET #unix_four_weeks_ago = UNIX_TIMESTAMP(curdate()) - 2419200;
SELECT *,FROM_UNIXTIME(timemodified,'%d-%m-%Y') FROM mod_users WHERE timemodified >= #unix_four_weeks_ago
My guess is that you want to split the user count per week according to the timemodified column. I would use the WEEK() function to do that.
The following SQL would add a weeknumber column to identify the week number:
SELECT WEEK(timemodified) weeknumber, dates.*
FROM dates
Then, if you want to get the distinct user count, you can simply use the following SQL:
SELECT WEEK(timemodified) weeknumber, COUNT(DISTINCT(userid)) users_count
FROM dates
GROUP BY weeknumber
You can also add a WHERE clause to get only certain weeks as you wish. So, to get the last 4 weeks from the 23-08-2015, I would do:
SELECT WEEK(timemodified) weeknumber, COUNT(DISTINCT(userid)) users_count
FROM dates
WHERE WEEK(timemodified) <= WEEK('2015-08-23')
AND WEEK(timemodified) > (WEEK('2015-08-23') - 4)
GROUP BY weeknumber
Let's hope I assumed correctly. :-)

Selecting data interval

I have a table that has date and id column. How can I select id's of 7 days interval?
My data is:
date id
2013-07-01 11
2013-07-02 22
2013-07-03 33
2013-07-04 33
2013-07-05 44
2013-07-06 44
2013-07-07 45
2013-07-08 46
2013-07-09 47
2013-07-10 48
2013-07-11 48
2013-07-12 49
2013-07-13 50
2013-07-14 51
2013-07-15 52
2013-07-16 52
2013-07-17 53
2013-07-18 53
2013-07-19 54
What I want is:
date id
2013-07-01 11
2013-07-08 46
2013-07-15 52
Thanks
SELECT date,id FROM table1 GROUP BY WEEK(`date`, 1)
http://sqlfiddle.com/#!2/b128c/1
the group by does not do the trick with (any) sql - ok mysql does - others wont allow this
SELECT date,id FROM table1 GROUP BY WEEK(`date`, 1)
would result in something like error: id is not part of group by ....
if you group by a col1 and not by col2 the database does not know what value you want for col2.
MySql seems to assume "if i do not group by others, take the smallest or first in databsse order'
If - and only if - you want the first (!) result - or what ever MySql decides to use for your missing 2nd grouping element, you are ok.
explanation:
assume this:
CREATE TABLE table1
(`id` int, `val` int );
INSERT INTO table1
(`id`, `val`)
VALUES
(1,99), --'!!!!'
(1,2),
(1,3),
(1,4),
(1,2),
(2,1),
(1,1),
(2,2),
(3,1),
(4,1)
;
See - please, there a 6 rows with 'id'=1, two with id '2' others unique
select id, val FROM table1 GROUP BY id
evaluates to:
ID VAL
1 99
2 1
3 1
4 1
this is only - probably - what you want and if it is a date you have a chance(!) the it will be what you want
to get a valid (without database intepret) result set you will have to use:
select id, some_aggregation_function(val) from table1 group by id
where aggregation is min, max or so.
the is some thing like :
select id, val FROM table1 a
where (id,val)=(select id, min(val) from table1 b where a.id=b.id)
if you want the minimum ....

How can I select the latest of three value types in a MySQL database?

Here is an example table:
ID time data type
0 0100 xyz 0
1 0200 xyz 1
2 0300 xyz 1
3 0400 xyz 2
4 0200 xyz 0
5 0500 xyz 2
6 0300 xyz 0
Data is added based on timestamp so that the last of each type has the latest time stamp.
I would like the result of a SELECT to be:
ID time data type
5 0500 xyz 2
2 0300 xyz 1
6 0300 xyz 0
And so the last of each 'type' is returned.
I can accomplish the above using three SELECT statements as follows:
SELECT time, data, type FROM table WHERE type=0 ORDER BY time DESC LIMIT 1
SELECT time, data, type FROM table WHERE type=1 ORDER BY time DESC LIMIT 1
SELECT time, data, type FROM table WHERE type=2 ORDER BY time DESC LIMIT 1
Is there a way to combine the above three SELECT statements into one?
Any help appreciated.
Chris
select m.ID, m.time, m.data, m.type
from (
select type, max(time) as MaxTime
from MyTable
group by type
) mm
inner join MyTable on mm.type = m.type
and mm.MaxTime = m.time