I need to split one date record into a several date records (dynamically, depending on a date range that overlaps) like this in MySQL:
input data:
level |start_time |end_time
1 2018-12-24 09:00:00 2018-12-25 09:00:00
Output result should look like:
level |start_time |end_time
1 2018-12-24 09:00:00 2018-12-25 00:00:00
1 2018-12-25 00:00:00 2018-12-25 09:00:00
Any help is much appreciated.
Try to initiate your sql code like this. It's a long shot but I hope it get you started somewhere.
select tx.col1
FROM
( (
SELECT start_time as col1 from t1
)
UNION
(
SELECT end_time as col1 from t1
)
) as tx
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.
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
I have an MySQL table, similar to this example:
c_id date value
66 2015-07-01 1
66 2015-07-02 777
66 2015-08-01 33
66 2015-08-20 200
66 2015-08-21 11
66 2015-09-14 202
66 2015-09-15 204
66 2015-09-16 23
66 2015-09-17 0
66 2015-09-18 231
What I need to get is count of periods where dates are in row. I don't have fixed start or end date, there can be any.
For example: 2015-07-01 - 2015-07-02 is one priod, 2015-08-01 is second period, 2015-08-20 - 2015-08-21 is third period and 2015-09-14 - 2015-09-18 as fourth period. So in this example there is four periods.
SELECT
SUM(value) as value_sum,
... as period_count
FROM my_table
WHERE cid = 66
Cant figure this out all day long.. Thx.
I don't have enough reputation to comment to the above answer.
If all you need is the NUMBER of splits, then you can simply reword your question: "How many entries have a date D, such that the date D - 1 DAY does not have an entry?"
In which case, this is all you need:
SELECT
COUNT(*) as PeriodCount
FROM
`periods`
WHERE
DATE_ADD(`date`, INTERVAL - 1 DAY) NOT IN (SELECT `date` from `periods`);
In your PHP, just select the "PeriodCount" column from the first row.
You had me working on some crazy stored procedure approach until that clarification :P
I should get deservedly flamed for this, but anyway, consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(date DATE NOT NULL PRIMARY KEY
,value INT NOT NULL
);
INSERT INTO my_table VALUES
('2015-07-01',1),
('2015-07-02',777),
('2015-08-01',33),
('2015-08-20',200),
('2015-08-21',11),
('2015-09-14',202),
('2015-09-15',204),
('2015-09-16',23),
('2015-09-17',0),
('2015-09-18',231);
SELECT x.*
, SUM(y.value) total
FROM
( SELECT a.date start
, MIN(c.date) end
FROM my_table a
LEFT
JOIN my_table b
ON b.date = a.date - INTERVAL 1 DAY
LEFT
JOIN my_table c
ON c.date >= a.date
LEFT
JOIN my_table d
ON d.date = c.date + INTERVAL 1 DAY
WHERE b.date IS NULL
AND c.date IS NOT NULL
AND d.date IS NULL
GROUP
BY a.date
) x
JOIN my_table y
ON y.date BETWEEN x.start AND x.end
GROUP
BY x.start;
+------------+------------+-------+
| start | end | total |
+------------+------------+-------+
| 2015-07-01 | 2015-07-02 | 778 |
| 2015-08-01 | 2015-08-01 | 33 |
| 2015-08-20 | 2015-08-21 | 211 |
| 2015-09-14 | 2015-09-18 | 660 |
+------------+------------+-------+
4 rows in set (0.00 sec) -- <-- This is the number of periods
there is a simpler way of doing this, see here SQLfiddle:
SELECT min(date) start,max(date) end,sum(value) total FROM
(SELECT #i:=#i+1 i,
ROUND(Unix_timestamp(date)/(24*60*60))-#i diff,
date,value
FROM tbl, (SELECT #i:=0)n WHERE c_id=66 ORDER BY date) t
GROUP BY diff
This select groups over the same difference between sequential number and date value.
Edit
As Strawberry remarked quite rightly, there was a flaw in my apporach, when a period spans a month change or indeed a change into the next year. The unix_timestamp() function can cure this though: It returns the seconds since 1970-1-1, so by dividing this number by 24*60*60 you get the days since that particular date. The rest is simple ...
If you only need the count, as your last comment stated, you can do it even simpler:
SELECT count(distinct diff) period_count FROM
(SELECT #i:=#i+1 i,
ROUND(Unix_timestamp(date)/(24*60*60))-#i diff,
date,value
FROM tbl,(SELECT #i:=0)n WHERE c_id=66 ORDER BY date) t
Tnx. #cars10 solution worked in MySQL, but could not manage to get period count to echo in PHP. It returned 0. Got it working tnx to #jarkinstall. So my final select looks something like this:
SELECT
sum(coalesce(count_tmp,coalesce(count_reserved,0))) as sum
,(SELECT COUNT(*) FROM my_table WHERE cid='.$cid.' AND DATE_ADD(date, INTERVAL - 1 DAY) NOT IN (SELECT date from my_table WHERE cid='.$cid.' AND coalesce(count_tmp,coalesce(count_reserved,0))>0)) as periods
,count(*) as count
,(min(date)) as min_date
,(max(date)) as max_date
FROM my_table WHERE cid=66
AND coalesce(count_tmp,coalesce(count_reserved,0))>0
ORDER BY date;
I have table Structure like this
id from to
1 2014-02-01 00:00:00 2014-02-28 00:00:00
2 2014-01-01 00:00:00 2014-01-30 00:00:00
3 2014-03-01 00:00:00 2014-03-30 00:00:00
and There is no date range overlapping in this
I'm trying to select record by passing a date which lie within the range
eg. passing date '2014-01-16' should return the record with id=2 as it falls within the range of the dates in this row, please guide me to solve this.
Thanks in advance
SELECT * FROM mytable
WHERE '2014-01-16' BETWEEN `from` AND `to`
SQLFiddle
SELECT id FROM table WHERE from <= '2014-01-16' AND to >= '2014-01-16'