How to compare datetime in same column in sql - mysql

I'm currently developing a function where I needto compare two datetime in a same column and if two values are equal then I need to rank it 1. If the next datetime is greater than current, I need to increment the rank to 2 and so on. I don't want to use Ranking functions as i am facing some issues when I use ranking functions. I need to take time also into account while comparing the dates. Please help me with this. Thanks in advance
Table
Date
2012-07-09 00:00:00.000
2012-07-09 00:00:00.000
2012-07-09 00:00:00.000
2014-06-01 00:00:00.000
2014-06-01 00:00:00.000
2014-06-01 00:00:00.000
2015-01-01 13:09:00.000
2015-01-01 13:09:00.000
2015-01-01 13:09:00.000
Desired Output
Date Qnum
2012-07-09 00:00:00.000 1
2012-07-09 00:00:00.000 1
2012-07-09 00:00:00.000 1
2014-06-01 00:00:00.000 2
2014-06-01 00:00:00.000 2
2014-06-01 00:00:00.000 2
2015-01-01 13:09:00.000 3
2015-01-01 13:44:00.000 4
2015-01-01 13:44:00.000 4

See if this works for you.
Usage : Select * from [dbo].usf_Rank
How it works : It builds a list of Dates in asc order and ranks them using an identity column while inserting into the helper table #Tbl in this manner :
1 D1
2 D2
3 D3
Then just inner join with the original table using the date column to expand and get the results as you wanted by returning a Table. (Using Table Valued Functions syntax )
CREATE Function [dbo].[usf_Rank]()
RETURNS #Results Table
(
D1 Datetime ,
RNK INT
)
AS
Begin
Declare #Tbl Table (ID INT IDENTITY(1,1) NOT NULL , D1 Datetime )
Declare #Tbl2 Table ( D1 DAtetime)
-- INERT INTO #Tbl2 (D1) SELECT DATE_COLUMN FROM REAL_TABLE -- I suppose this would be how you would actually use it instead of the fixed date values that I used for illustration below.
INSERT INTO #Tbl2 (D1) Values
('2012-07-09 00:00:00.000'),
('2012-07-09 00:00:00.000'),
('2012-07-09 00:00:00.000'),
('2014-06-01 00:00:00.000'),
('2015-01-01 13:44:00.000'),
('2015-01-01 13:44:00.000'),
('2014-06-01 00:00:00.000'),
('2014-06-01 00:00:00.000'),
('2015-01-01 13:44:00.000')
-- Generate the Rankings by using ID col which is identity column
insert into #Tbl select D1 from #Tbl2 group by D1 Order by D1
-- Expand by joining with orig table to get results in the format you want
insert into #Results
select t1.D1, t1.ID from #Tbl t1 inner join #Tbl2 T2 ON T1.D1 = T2.D1
RETURN
END
Go

Related

MYSQL , Count week wise and also show sum with empty dates

I have two tables
Table_1 : Routes_Day_plan
Date Status_Id
------------------------
2019-06-09 1
2019-06-10 2
2019-06-09 2
2019-06-11 3
2019-06-14 4
2019-06-14 6
2019-06-15 8
Table_2 : Codes
id code
-------
1 Leave
2 Half_leave
3 Holiday
4 Work
5 Full_Hours
Now my task is to count week wise from table 1 where code (from second table) = Leave,Half_leave,work and than also show the sum , and where date not found show 0 , i write this query it's return data but not empty dates can someone please help ,
My Query:
select COUNT(*) as available, DATE(date)
from Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
group by date
UNION ALL
SELECT COUNT(date), 'SUM' date
FROM Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
Result Something Like ,
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
2 2019-06-14
2 2019-06-15
17 SUM
I want like this
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
0 2019-06-13
2 2019-06-14
2 2019-06-15
17 SUM
Your best bet here would be to have a Date Dimension/Lookup table which contains pre-populated dates for the entire year. By joining your record table to this lookup, you essentially allocate your data to each date that actually exist (ex. 2019-06-13) and if your data is not found in the lookup, you will find a null in that field.
The Count function will count a null as a 0. Just make sure you group on the date field from your lookup table and not from your record table.
Make a table, a date dimension that contains all the dates value, from beginning to end. Like this:
Set EndDate = '2099-01-01';
Set RunDate = '1900-01-01';
WHILE RunDate <= EndDate DO
insert into dim_date
(`DATE`)
select
RunDate as DATE
;
Set RunDate = ADDDATE(RunDate,1);
END WHILE;
Create temporary table with dim_date left join Routes_Day_plan and set Status as 0 maybe for record that dont match. Use this temporary table then instead of Routes_Day_plan in your queries.

Self join table current row and next row horizontally in MySQL

I am implementing a functionality wherein I have to delete current row based on values present in next row of same table.
I have records with columns: id, created_at and mark.
I need delete all records,
WHERE currentrow.mark != nextrow.mark or (currentrow.mark = nextrow.mark and currentrow.created_at= '2000-01-01 00:00:00.000')
i.e. only records with next rows have not same mark or records with next row have same mark and created_at = '2000-01-01 00:00:00.000'
id created_at mark
235 1990-01-01 00:00:00.000 5 /delete
236 1990-01-01 00:00:00.000 5 /delete
237 1990-01-01 00:00:00.000 5
238 2016-10-10 23:45:40.000 5
id created_at mark
312 1990-01-01 00:00:00.000 8 /delete
313 2016-01-09 18:00:00.000 6
314 1990-01-01 00:00:00.000 4 /delete
315 1990-01-01 00:00:00.000 7
316 2016-10-10 23:45:40.000 7
Kindly help to retrieve table every row joined next rows of same table horizontally in result set.
One way to join the next row is
INNER JOIN `tablename` AS `next` ON `next`.`id` = (
SELECT MIN(id) FROM `tablename` WHERE `tablename`.`id` > `current`.`id`
)
AND (`next`.`mark` != `current`.`mark`
OR `next`.`created_at` = '2000-01-01 00:00:00.000') // maybe 1990?
I did not understand the delete conditions completely. But I will give answer to your last question
"Kindly help to retrieve table every row joined next rows of same table horizontally in result set."
SELECT * FROM
(SELECT (#rowid1 := #rowid1 + 1) firstSeq, id firsttableid, created_at firsttablecreated_at, mark firsttablemark FROM `mytable`
JOIN (SELECT #rowid1 := 0) a) table1
LEFT JOIN (SELECT (#rowid2 := #rowid2 + 1) secondSeq, id secondtableid, created_at secondtablecreated_at, mark secondtablemark FROM `mytable`
JOIN (SELECT #rowid2 := 0) a) table2 ON table1.firstSeq = table2.secondSeq - 1 and **(your conditions)**
This will give you the result set as you need. Now you may add your required conditions to convert to delete

MySQL Select distinct column for each Relational_ID where largest timestamp below X

I am attempting to find all of the individual rows with a distinct or unique In_Column value for each Item_ID (our relational_id here) where Item_Table = 'X' and the Timestamp of the row is the highest for this distinct In_Column + Item_ID + Item_Table but lower than the supplied value.
sample_table
In_Column End_Value Item_Table Item_ID Timestamp
----------------------------------------------------------
Length 3 Pipe 3 2016-07-29 09:00:00
Length 2 Pipe 3 2016-07-30 09:00:00
Length 5 Pipe 4 2016-07-30 11:00:00
Kg 12 Pipe 3 2016-07-29 09:00:00
Kg 25 Steel 1 2016-07-29 09:00:00
Ideal result if supplied date was current time and Item_Table = 'Pipe'
In_Column End_Value Item_Table Item_ID Timestamp
----------------------------------------------------------
Length 2 Pipe 3 2016-07-30 09:00:00
Length 5 Pipe 4 2016-07-30 11:00:00
Kg 12 Pipe 3 2016-07-29 09:00:00
The ordering doesn't matter as I will be casting the return (which will be big, there is a lot of matching rows on the table) into an array following fetching.
Sorry for not providing an example query, I have played around with some concatenated LEFT JOINs but their execution time was understandably quite long and the result set wasn't as specific as intended.
This should work for you
SELECT
`t1`.*
FROM
`your_table` `t1`
INNER JOIN
(
SELECT
`Item_ID`,
`In_Column`,
MAX(`Timestamp`) AS `latest`
FROM
`your_table`
WHERE
`Item_Table` = 'Pipe' AND
`Timestamp` < 'Supplied Time'
GROUP BY
`Item_ID`, `In_Column`) `t2`
ON
`t1`.`Item_ID` = `t2`.`Item_ID` AND
`t1`.`In_Column` = `t2`.`In_Column` AND
`t1`.`Timestamp` = `t2`.`latest`
WHERE
`Item_Table` = 'Pipe'
Just replace your_table with correct table name.

MYSQL -How to set zero if no row in select date

I want to select value from given date and same time if no row in that date then it should return 0 in that specific date. here is my query
SELECT
sum(`value`) AS `VALUE`,
serverTimeStamp AS date
FROM
table1 t1
WHERE
serverTimeStamp BETWEEN CONVERT_TZ(
'2016-03-21 00:00:01',
'+00:00',
'-05:30'
)
AND CONVERT_TZ(
'2016-03-25 23:30:36',
'+00:00',
'-05:30'
)
GROUP BY
YEAR (date),
MONTH (date),
WEEK (date),
DAY (date)
ORDER BY
date ASC;
Output :
value date
96 2016-03-21 00:00:01
76 2016-03-23 00:00:01
56 2016-03-25 00:00:01
Expected Output :
value date
96 2016-03-21 00:00:01
0 2016-03-22 00:00:01
76 2016-03-23 00:00:01
0 2016-03-24 00:00:01
56 2016-03-25 00:00:01
Any idea to achieve this?
table1 :
**id value serverTimeStamp**
1 96 2016-03-21 00:00:01
2 76 2016-03-23 00:00:01
3 56 2016-03-25 00:00:01
but what i am expecting in query if there is no row in given date then it should be 0 and specific date like below
value date
96 2016-03-21 00:00:01
0 2016-03-22 00:00:01
76 2016-03-23 00:00:01
0 2016-03-24 00:00:01
56 2016-03-25 00:00:01
You need to create a table storing your possible dates and then LEFT JOIN your query to it, so that every date that is missing from your query would still be included in the output, but with the value 0.
How to generate data into table with dates: Generate series equivalent in MySQL
You just need to alter this query to include an INSERT INTO your table with dates.
Then, depending on how you insert your date (with time - if it's static coming from your query, or without time - if it's changing) you need to join that table with your existing query on the column value if it contains time, or if it doesn't, on the date part extracted from serverTimeStamp from your query
Create a stored procedures and do like below to get your desired output
create table temp_data
(
id int,
value int,
server_date datetime
);
Drop temporary table if exists temp_generate_dates;
create temporary table temp_generate_dates
(
temp_date datetime
);
insert into temp_generate_dates
select adddate('2016-03-21 00:00:01', #num:=#num+1) as date
from
temp_data,
(select #num:=-1) num
limit 5;
select coalesce(t1.value,0),t2.temp_date from temp_generate_dates t2
left join temp_data t1 on t2.temp_date = t1.server_date ;

MySQL: change user variable for each selected row

I'm trying to select the first ten empty time slots between appointments in a MySQL database.
The appointment table has basically 3 fields: appointment_id INT, startDateTime DATETIME and endDateTime DATETIME.
We can imagine some data like this (for simplicity's sake, I've left the date part out of the datetime so let's consider these hours are in the same day). Also the data is ordered by startDateTime:
4 | 09:15:00 | 09:30:00
5 | 09:30:00 | 09:45:00
8 | 10:00:00 | 10:15:00
3 | 10:30:00 | 10:45:00
7 | 10:45:00 | 11:00:00
2 | 11:00:00 | 11:15:00
1 | 11:30:00 | 12:00:00
So my goal is to extract:
00:00:00 | 09:15:00
09:45:00 | 10:00:00
10:15:00 | 10:30:00
11:15:00 | 11:30:00
In ended up doing this:
SET #myStart = '2012-10-01 09:15:00';
SET #myEnd = NULL;
SET #prevEnd = NULL;
SELECT a.endDateTime, b.startDateTime, #myStart := a.endDateTime
FROM appointment a, appointment b, (
SELECT #myEnd := min(c.startDateTime)
FROM appointment c
WHERE c.startDateTime >= #myStart
ORDER BY startDateTime ASC
) as var ,
(SELECT #prevEnd := NULL) v
WHERE a.appointment_id = (
SELECT appointment_id
FROM (
SELECT appointment_id, max(endDateTime), #prevEnd := endDateTime
FROM appointment d
WHERE (#prevEnd IS NULL OR #prevEnd = d.startDateTime)
AND d.startDateTime >= #myEnd
) as z
)
AND b.startDateTime > a.endDateTime
ORDER BY b.startDateTime ASC LIMIT 0,10;
This doesn't return any result. I guess it's because of an incorrect initialization of my user defined variables (just discovered them and I may be using them completely wrong).
If I run only the first subquery whose goal is to initialize #myEnd at the first appointment after #myStart, I can see that it in fact returns 09:15:00.
The second subquery (SELECT #prevEnd := NULL) v is meant to set #prevEnd back to NULL each time a row is selected in the main query. I'm not quite sure it works like that...
The last subquery is meant, starting with a null #prevEnd and an initialized #myEnd, to select the appointment after which there is a gap. I could verify that it works too if separated from the rest of the query.
Do you have any advice on what I could do to fix the query, on how I could/should do it otherwise or on wheter it's even possible or not?
Thanks very much in advance.
Edit: I have edited it like this:
SELECT *
FROM (
SELECT COALESCE( s1.endDateTime, '0000-00-00 00:00:00' ) AS myStart, MIN( s2.startDateTime ) AS minSucc
FROM appointment s1
RIGHT JOIN appointment s2 ON s1.endDateTime < s2.startDateTime
AND s1.radiologyroom_id = s2.radiologyroom_id
WHERE s1.startDateTime >= '2012-10-01 00:00:00'
AND s1.radiologyroom_id =174
AND s1.endDateTime < '2013-01-01 00:00:00'
GROUP BY myStart
ORDER BY s1.startDateTime
)s
WHERE NOT
EXISTS (
SELECT NULL
FROM appointment
WHERE startDateTime >= myStart
AND endDateTime <= minSucc
AND radiologyroom_id =174
ORDER BY startDateTime
)
and it retrieves 369 rows in 14.6 seconds out 6530 records
If there are no gaps between ids, and id is always increasing, you could use this:
SELECT coalesce(s1.endDateTime, '0000-00-00 00:00:00'), s2.startDateTime
FROM
slots s1 right join slots s2
on s1.appointment_id=s2.appointment_id-1
WHERE coalesce(s1.endDateTime, '0000-00-00 00:00:00')<s2.startDateTime
LIMIT 10
EDIT: you can also try this:
SELECT * FROM
(SELECT
coalesce(s1.endDateTime, '0000-00-00 00:00:00') as start,
min(s2.startDateTime) minSucc
from slots s1 right join slots s2
on s1.endDateTime<s2.startDateTime
group by start) s
WHERE
not exists (select null
from slots
where startDateTime>=start
and endDateTime<=minSucc)
EDIT2: I admit that I am not much pratical with queries with variables, but this looks like that it could work:
select d1, d2 from (
select
#previous_end as d1,
s.startDateTime as d2,
#previous_end:=s.endDateTime
from (select startDateTime, endDateTime from slots order by startDateTime) s,
(select #previous_end := '0000-00-00 00:00:00') t) s
where d1<d2