Fetch records between hours For example records below, i have tried to fetch the data between morning hours(07:30 to 19:30) and evening hours(19:30 to 07:30), but getting blank results while querying for evening results
migi_date|service_number
---------|-------
11:15:00 | 23KPLKS
18:32:42 | KPLSKS3
10:02:04 | OSNSJS0
23:79:00 | QIW8SKD
11:08:00 | 28SOKSL
22:29:00 | 2UJSOPD
SELECT * FROM `report` WHERE `migi_date` BETWEEN '07:30:00' AND '19:30:00';
migi_date|service_number
---------|-------
11:15:00 | 23KPLKS
18:32:42 | KPLSKS3
10:02:04 | OSNSJS0
11:08:00 | 28SOKSL
i can able to fetch data between '07:30:00' AND '19:30:00', but for '19:30:00' to '07:30:00' getting blank.
using same query with hour change
SELECT * FROM `report` WHERE `migi_date` BETWEEN '19:30:00' AND '07:30:00';
Please suggest the query.
Maybe these two queries could fit...? With the principle that I mentioned in the comment
-- Morning
SELECT * FROM my_table WHERE my_hour BETWEEN '07:30:00' AND '19:30:00';
-- Evening
SELECT * FROM my_table WHERE (my_hour BETWEEN '19:30:01' AND '23:59:59') or (my_hour BETWEEN '00:00:00' AND '07:29:59');
Query built from dummy names.
You should take in consideration the column type.
If your column is time which has range value -838:59:59 to 838:59:59
therefore, you can't expect mysql to use it as 24h round.
#juan is almost right, you need 2 condition
`migi_date` BETWEEN '19:30:00' AND '23:59:59'
OR
`migi_date` BETWEEN '00:00:00' AND '07:30:00'
The same apply if it is a varchar().
You need to adjust seconds if you don't want to have boundaries values in both result
Related
I have the following SQL:
set #arbitraryMin = 'two weeks ago';
set #myDesiredMinimumTime = 'thisMorning';
select distinct order, box from db.table
where scantime >= #arbitraryMin
having min(scantime) >= #myDesiredMinimumTime
Essentially, we have a system where it is possible that there are multiple scans for a distinct box/order combo. I only want to get the ones where the minimum scantime is >= #myDesiredMinimumTime. The query above returns two columns with no values in them. I can do this with a sub query, but I was wondering if there was a way to do this without using one.
I am no SQL guru, so I appreciate any help. Table sample (sorry for format):
scantime | Order | Box
2017-06-29 12:34:56 | 123456 | 123
2107-06-29 12:12:12 | 123456 | 124
2017-06-28 14:50:00 | 123456 | 123
Note the two duplicate order/box combos on different days on rows 1 and 3. If I input my query with #arbitraryMin = '2017-06-28 00:00:00' and #myDesiredMinimumTime = '2017-06-29 00:00:00', I only want to get the last two rows, as the top one is a duplicate scan at a different time.
Thank you
That's a invalid SQL. You can't have a HAVING clause without GROUP BY. So the below line is faulty
having min(scantime) >= #myDesiredMinimumTime
You should put that condition in WHERE clause only
where scantime >= #arbitraryMin
and (select min(scantime) from db.table) >= #myDesiredMinimumTime
Thank you to Rahul.
I have found a solution:
select distinct order, box from db.table
where scantime <= #maxTime
group by ordernumber, boxnumber
having min(scantime) >= #myDesiredMinimumTime
I have a table that stores scores of each player based on date. A player can have multiple scores saved for same date as he proceeds through the game. Example data is for date 2015-10-01 is:
id player_id score score_date
------------------------------------------------------
1 100 3200 2015-10-10 10:10:37
2 101 1750 2015-10-10 10:12:42
3 100 1100 2015-10-10 10:19:50
4 102 4100 2015-10-11 10:24:22
5 101 3000 2015-10-09 10:32:44
As you can see here, player 100 has two scores in this table. His final score for the date is 1100. player 101 has two scores too, but for the selected date he only has one score. player 102 does not have any score for the selected date.
How can I write a query that will fetch me the final score record of the each player for that particular date? The result I want is:
player_id score date
------------------------------------------------------
100 1100 2015-10-10 10:19:50
101 3000 2015-10-09 10:32:44
I tried to frame this question earlier, but ended up messing up the actual point and it turned into a different question (for which I got an excellent answer btw).I hope someone will help me solve this problem because I am really stuck here :(
schema
create table scores
( id int auto_increment primary key,
player_id int not null,
score int not null,
score_date datetime not null
);
insert scores(player_id,score,score_date) values
(100, 3200, '2015-10-10 10:10:37'),
(101, 1750, '2015-10-10 10:12:42'),
(100, 1100, '2015-10-10 10:19:50'),
(102, 4100, '2015-10-11 10:24:22'),
(101, 3000, '2015-10-09 10:32:44'),
(105, 6666, '2015-10-09 10:00:44');
Last score thru 2015-10-10 achieved on any date
SELECT a.player_id,a.score
FROM scores a
JOIN
( SELECT player_id, MAX(score_date) as weCareAbout
FROM scores
where score_date<date('2015-10-11')
GROUP BY player_id
) b
ON b.player_id=a.player_id and b.weCareAbout=a.score_date
order by a.player_id;
+-----------+-------+
| player_id | score |
+-----------+-------+
| 100 | 1100 |
| 101 | 1750 |
| 105 | 6666 |
+-----------+-------+
Last score on 2015-10-10 and scores only on that date
SELECT a.player_id,a.score
FROM scores a
JOIN
( SELECT player_id, MAX(score_date) as weCareAbout
FROM scores
where date(score_date)='2015-10-10'
GROUP BY player_id
) b
ON b.player_id=a.player_id and b.weCareAbout=a.score_date
order by a.player_id;
+-----------+-------+
| player_id | score |
+-----------+-------+
| 100 | 1100 |
| 101 | 1750 |
+-----------+-------+
Keeping in mind that I think your expected results are wrong. Their final score, not the high score.
It's a pivot-table-sort-of-problem, for which MySQL unfortunately isn't super efficient.
Subqueries and ORDER BY ... LIMIT 1 can get you the results you're after, but performance will drop substantially.
For an inefficient solution (using subqueries) for example: (Nowhere to test this, syntax might not be spot on...)
SELECT player_id, score
FROM scores
INNER JOIN
(
SELECT
MAX(`date`) AS `latestScoreDateTime`,
player_id
FROM scores
WHERE DATE(`date`) = '2015-10-10'
GROUP BY player_id
) AS sub1 ON (
sub1.lastestScoreDateTime = scores.date AND
sub1.player_id = scores.player_id
)
But put an EXPLAIN on the front of that - and you'll see performance isn't good at all.
Personally (having worked on some big databases with big datasets and these sorts of problems to solve, all requiring speed and efficiency) I'd handle all the database inserts through a stored procedure (or your own data-access-layer in your application, or [shudder] through triggers).
This abstraction layer would maintain a "latestForDate" field. A stored procedure can do this in a transactionally safe manner.
I've not got a test area to prove this - but the syntax would look something approximately like this:
DELIMTIER $$
CREATE PROCEDURE spAddPlayerScore (IN fin_playerId INT UNSIGNED, IN fin_score INT UNSIGNED)
BEGIN
DECLARE pToday DATETIME;
START TRANSACTION;
SET pToday = CURDATE();
UPDATE scores SET latest_for_date=NULL
WHERE latest_for_date=pToday AND player_id=fin_playerId;
INSERT INTO scores SET
latest_for_date=pToday,
score=fin_score,
player_id=fin_playerId;
COMMIT;
END$$
Thusly you (transactionally safely) maintain a denormalised (efficient for reading!) way of getting the highest score:
SELECT * FROM scores WHERE latest_for_date='2015-10-10' GROUP BY player_id;
Try this (not tested, could have syntax errors):
CREATE TEMPORARY
TABLE t1 (player_id int not null, score int not null, score_date datetime),UNIQUE KEY(player_id,score_date));
REPLACE INTO t1 SELECT player_id, score, score_date
FROM tbl_name
WHERE DATE(score_date) = '2015-10-01' order by player_id,score_date;
SELECT * FROM t1;
SELECT *
FROM (
SELECT player_id, score, score_date
FROM player
ORDER BY score_date DESC
) temp
GROUP BY player_id, score_date
I have three table Like this:
members_tbl
id | Fullname | Email | MobileNo
attendance_in_tbl
id | member_id | DateTimeIN
attendance_out_tbl
id | member_id | DateTime_OUT
I want to select all members for date: 2014-03-10 by this query:
SELECT
attendance_in.EDatetime,
members_info.mfullname,
attendance_out.ODatetime
FROM
attendance_in
LEFT JOIN members_info ON members_info.id = attendance_in.MemID
LEFT JOIN attendance_out ON attendance_out.MemID = attendance_in.MemID
WHERE date(attendance_in.EDatetime) OR date(attendance_out.ODatetime) = "2014-03-10"
But it give me different results in Attendace_out Results
You have a mistake in your query.
You wrote:
WHERE date(attendance_in.EDatetime) /* wrong! */
OR date(attendance_out.ODatetime) = "2014-03-10"
This is wrong, as the first expression date(attendance_in.EDatetime) always evaluates to true.
You may want
WHERE date(attendance_in.EDatetime) = "2014-03-10"
OR date(attendance_out.ODatetime) = "2014-03-10"
But, this is guaranteed to perform poorly when your attendance_in and attendance_out tables get large, because it will have to scan them; it can't use an index.
You may find that it performs better to write this:
WHERE (attendance_in.EDatetime >='2014-03-10' AND
attendance_in.EDatetime < '2014-03-10' + INTERVAL 1 DAY)
OR (attendance_out.EDatetime >='2014-03-10' AND
attendance_out.EDatetime < '2014-03-10' + INTERVAL 1 DAY)
That will check whether either the checkin our checkout time occurs on the day in question.
It seems as though my gap detection is just picking up whatever I set as the timedifference and doing it every interval based on that.
So here's an explanation of my data structure and what I'm after:
I have a database that's set up like this:
(Schema Name)
Historical
-CID int UQ AI NN
-ID Int PK
-Location Varchar(255)
-Status Varchar(255)
-Time datetime
My data comes in looking something like this (example 5 rows for selected ID)
433275 | 97 | MyLocation | OK | 2013-08-20 13:05:54
433275 | 97 | MyLocation | OK | 2013-08-20 13:00:54
433275 | 97 | MyLocation | OK | 2013-08-20 12:25:54
433275 | 97 | MyLocation | OK | 2013-08-20 12:20:54
433275 | 97 | MyLocation | OK | 2013-08-20 12:15:54
In the case above you'll notice that I'm missing data from 12:25:54 -> 13:00 for ID 97. I am trying to write a report that will tell me the: Start of downtime, Duration of DownTime, and End of Downtime (which I've been handling in php by adding timediff to Time)
Here's my code (php -> mysql) (non-working) as it stands now:
select *from (
SELECT
y.*,
TIMESTAMPDIFF(MINUTE, #prevDT, `Time`) AS timedifference,
#prevDT := `Time`
FROM ddHistorical y,
(SELECT #prevDT:=(SELECT MIN(`Time`) FROM ddHistorical)) vars
Where ID = '". mysql_real_escape_string($ID)."'
HAVING timedifference > 16
) s
order by Time desc
Limit 25";
You need two levels of subquery:
SELECT *
FROM (
SELECT y.*,
TIMESTAMPDIFF(MINUTE, #prevDT, `Time`) AS timedifference,
#prevDT := `Time`
FROM (SELECT *
FROM ddHistorical
WHERE ID = '97'
ORDER BY `Time`) y,
(SELECT #prevDT:=(SELECT MIN(`Time`) FROM ddHistorical)) vars) z
WHERE timedifference > 16
LIMIT 25
I'm actually not sure why the outermost level is needed. I tried without it (i.e. starting with SELECT y.*) and using HAVING timedifference > 16. For some reason, this reported a single row with timedifference = 45. But if I removed that HAVING clause, it showed all the rows, with the gap reported as 35 minutes. Usually, there's no difference between
SELECT ... HAVING <cond>
and
SELECT * FROM (SELECT ...) WHERE <cond>
I'm not sure why this query violates the rule -- I suspect it has something to do with the user-variables.
EDIT:
I think I've figured out why it didn't work with HAVING. MySQL is apparently evaluating that condition as soon as it calculates the timedifference column for each row, and discarding the row. When timedifference <= 16, it doesn't bother calculating the rest of the columns in the SELECT clause, so it never does #prevDT := Time. So until it gets past that condition, it's always comparing with MIN(Time).
Moving the timedifference check into an outer query forces it to calculate all the differences before filtering.
SQLFIDDLE
Please try this:
"
SELECT y.*,
TIMESTAMPDIFF(MINUTE, y.prevDT, y.`Time`) AS timedifference
FROM (SELECT w.*, (SELECT MAX(x.`Time`)
FROM ddHistorical x
WHERE x.ID = w.ID
AND x.`Time` < w.`Time`) AS prevDT
FROM ddHistorical w
WHERE w.ID = '". mysql_real_escape_string($ID)."') y
WHERE TIMESTAMPDIFF(MINUTE, y.prevDT, y.`Time`) > 16
ORDER BY y.`Time` DESC
LIMIT 25";
In this example, I am collecting some engine data on a car.
Variables
--------------------------------------
id | name
--------------------------------------
1 Headlights On
2 Tire Pressure
3 Speed
4 Engine Runtime in Seconds
...
Values
--------------------------------------
id | var_id | value | time
--------------------------------------
1 1 1 2013-05-28 16:42:00.100
2 1 0 2013-05-28 16:42:22.150
3 2 32.0 2013-05-28 16:42:22.153
4 3 65 2013-05-28 16:42:22.155
...
I want to write a query that returns a result set something like the following:
Input: 1,2,3
Time | Headlights On | Tire Pressure | Speed
---------------------------------------------------------------
2013-05-28 16:42:00 1
2013-05-28 16:42:22 0 32 65
Being able to modify the query to include only results for a given set of variables and at a specified interval say (1 second, 1 minute or 5 minutes) are also really important for my use case.
How do you write a query in T-SQL that will return a time-aggregated multi column result set at a specific interval?
1 minute aggregate:
SELECT {edit: aggregate functions over fields here} FROM Values WHERE {blah} GROUP BY DATEPART (minute, time);
5 minute aggregate:
SELECT {edit: aggregate functions over fields here} FROM Values WHERE {blah} GROUP BY
DATEPART(YEAR, time),
DATEPART(MONTH, time),
DATEPART(DAY, time),
DATEPART(HOUR, time),
(DATEPART(MINUTE, time) / 5);
For the reason this latter part is so convoluded, please see the SO post here: How to group time by hour or by 10 minutes .
Edit 1:
For the part "include only results for a given set of variables", my interpretation is that you want to to isolate Values with var_id being within a specified set. If you can rely on the variable numbers/meanings not changing, the common SQL solution is the IN keyword (http://msdn.microsoft.com/en-us/library/ms177682.aspx).
This is what you would put into the WHERE clause above, e.g.
... WHERE var_id IN (2, 4) ...
If you can't rely on knowing the variable numbers but are certain about their names, you can replace the set by a sub-query, e.g.:
... WHERE var_id IN (SELECT id FROM Variables WHERE name IN ('Tire Pressure','Headlights On')) ...
The alternative interpretation is that you actually want to aggregate based on the variable ids as well. In this case, you'll have to include the var_id in your GROUP BY clause.
To make the results more crosstab-like, I guess you'll want to order by time aggregate that you're using. Hope that helps more.
Try
SELECT
VehicleID
, Case WHEN Name = 'Headlights on' THEN 1
Else 0 END ' as [Headlights on]
, Case WHEN Name = 'Tyre pressure' THEN Value
Else CAST( NULL AS REAL) END ' as [Tyre pressure]
, DateName(Year, DateField) [year ]
FROM
Table
ETC
Then agrregate as required
SELECT
VehicleID
, SUM([Headlights on]) SUM([Headlights on],
FROM
(
QUery above
) S
GROUP BY
VehicleID
, [Year]