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

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 ;

Related

MySQL Split date range into separate records

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

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.

How to compare datetime in same column in sql

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

MySQL get count of periods where date in row

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;

SQL : Select record by passing a date within the range

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'