MSSQL Aggregated time query with multiple columns - php

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]

Related

mysql fetch data between hours [hh:mm:ss]

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

SQL Server Case with Session

I have an issue where I'm trying to show a result based on a time frame being either greater than 24 hours, greater than 18 hours or less than 18 hours where a My query thus far is written as
SELECT MAX(CASE WHEN DATEDIFF(HH,DATEADD(SECOND, inc.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 24 then 2
WHEN DATEDIFF(HH,DATEADD(SECOND, inc.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 18 then 1
Else 0 End) as DIFFERENCE
FROM dbo.HELP_DESK as inc
WHERE inc.LOGIN_ID in "some user"
and NOT EXISTS (SELECT work.Description from dbo.WORKLOG as work WHERE
work.INCIDENT_NUMBER = inc.INCIDENT_NUMBER
and work.WORK_LOG_TYPE = '16000'
and work.WORK_LOG_SUBMITTER in "User Group")
UNION ALL
SELECT MAX(CASE WHEN DATEDIFF(HH,DATEADD(SECOND, chg.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 24 then 2
WHEN DATEDIFF(HH,DATEADD(SECOND, chg.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 18 then 1
Else 0 End) as DIFFERENCE
FROM dbo.INFRASTRUCTURE_CHANGE as chg
WHERE chg.ASLOGID in "some user"
and NOT EXISTS (SELECT work.Description from dbo.WORKLOG as work WHERE
work.CHANGE_ID = chg.CHANGE_ID
and work.WORK_LOG_TYPE = '31000'
and work.WORK_LOG_SUBMITTER in "User Group")
My output in this example is:
+------------+
| DIFFERENCE |
+------------+
| 2 |
| 2 |
+------------+
I have multiple values >24 so obviously due to the union Im showing two separate values correctly as 2. However, what I want to do is somehow group them so I have a single output of 2, 1 or 0 that I can then output to a PHP session.
some form of count or group by both seem to fail unless I'm incorrectly grouping. There's also probably a better way of doing this but I appear to be taking the long road round.
Appreciate any pointers in taking me forward.
A simple change from UNION ALL to UNION returned the single result I was after to output a session value

Number of 1 time,2 times, 3 times, n times column entries in table in php mysql

Have Table :
id userid type created_date
1 4353535 1 04-06-2014
2 4353536 0 06-06-2014
3 4353537 1 11-06-2014
4 4353538 1 11-06-2014
5 4353539 0 19-06-2014
7 4353541 1 01-06-2014
10 4353544 1 12-06-2014
11 4353535 1 06-06-2014
12 4353536 1 10-06-2014
13 4353537 1 12-06-2014
What I Want : (with in date range)
How much user have single time entry with type 1
How much user have double time entry with type 1
How much user have triple time entry with type 1
How much user have four time entry with type 1
How much user have n time entry with type 1
(PHP & MYSQL)
First get the count for each user, then from that group the entrycount you can get your expected output
select EntryCount, count(userid) from (Select userid, count(id) as Entrycount from myentry group by userid where type=1) as sq group by Entrycount
This will work try
First, get the number of entries per user. Then, get the number of users grouped by number of entries.
SELECT numEntries, COUNT(*) AS numUsers
FROM (
SELECT userid, COUNT(*) AS numEntries
FROM tablename
WHERE type = 1
GROUP BY userid
) tbl
GROUP BY numEntries
Simplified demo
Demo with your data

MySQL querying date range

Here's my database (free rooms in a hotel, simplified)
rooms_available:
id date_available room_id
================================
1 2013-12-19 2
2 2013-12-20 2
3 2013-12-21 2
4 2013-12-22 2
5 2013-12-23 2
6 2013-12-25 3
rooms:
id name minimal_range
================================
2 Apartment A 5
3 Apartment B 1
I want to query all rooms which are available between 2013-12-20 and 2013-12-22
My query is like:
select *
from rooms_available
where (date='2013-12-20' OR date='2013-12-21' OR date='2013-12-22')
My questions:
is there a more comfortable way? when the date range will be like 2 weeks, the query will also be very long (which will take much longer for querying)
would it be possible to consider minimum ranges - for example: room_id 2 is only available for at least 5 nights (see table "rooms") -> so above query should return no records
Thanks
date >= '2013-12-20' and date <= '2013-12-22'
SELECT * FROM rooms_available WHERE `date_available` BETWEEN "2013-12-20 " AND "2012-03-31"
I didn't test this but it should point you in the right direction especially for the second part of your question about minimal range.
SELECT t1.id as id, t1.date_available as date_available, t1.room_id
FROM rooms_availble as t1 JOIN rooms as t2 on t1.room_id = t2.id
WHERE t1.date_available BETWEEN DATE('2013-12-20') AND DATE('2012-03-31') AND
t2.minimal_range <= datediff('2013-12-22', '2012-12-20');
The mysql datediff function will return the number of days between two dates then you can just compare it with the minimal_range from the rooms join table. Also you might consider binding the start and end dates to variables so that you only have to write each date once.

MYSQL query closest match from a second table

Hi I have 2 tables structured as follows
cdr
src | bill sec | clean_dst
------------------------------
100 | 10 | 18006927753
100 | 22 | 18006927753
100 | 9 | 441138973356
dialing_codes
id | dial_code | tele2id
-----------------------------
1 | 1 | 1422
2 | 1800 | 1433
3 | 441 | 1024
4 | 4413 | 1086
I need to get the tele2id for the closest match in dial_code against clean_dst my best effort so far is
$query = "SELECT tele2id, dial_code FROM dialing_codes ORDER by dial_code DESC";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
while($row = $result->fetch_assoc()) {
$tele2id = $row['tele2id'];
$dialcode = $row['dial_code'];
$query2 = "SELECT clean_dst FROM cdr WHERE clean_dst LIKE '".$dialcode."%'";
$result2 = $mysqli->query($query2) or die($mysqli->error.__LINE__);
while($row2 = $result2->fetch_assoc()) {
Which I thought was working but on closer inspection it only returns the correct result the first time if a clean_dst is repeated
eg
clean_dst dial_code tele2id
18006927753 1800 1433
18006927753 1 1422
What am i doing wrong? Thanks
If it helps I need the result with the most matching digits?
Although not in php, this one sql can handle your first and secondary query all in one... AND properly handle returning the longest matching entry per dial.
select
PQ.clean_dst,
PQ.dial_code,
PQ.tele2id,
#Rank := if( #lastDst = PQ.clean_dst, #Rank +1, 1 ) as dialRank,
#lastDst := PQ.clean_dst as ForNextRowCompare
from
( SELECT distinct
cdr.clean_dst,
dc.dial_code,
dc.tele2id,
length( trim( dc.dial_code )) as Longest
from
cdr
JOIN dialing_codes dc
on cdr.clean_dst like concat( dc.dial_code, '%' )
order by
cdr.clean_dst,
Longest DESC ) PQ,
( select #lastDst := '',
#Rank := 0 ) sqlvars
having
dialRank = 1
The first part is the inner query resulting in alias "PQ" (preQuery). It is getting a list of distinct combinations for any call data record to its matching POSSIBLE dial codes. Critical component is to put the order by each phone number dialed, THEN based on the longest dial code in descending order. This will put your "1800" at the top of the list per phone number using it.
Next comes the outer query where the MySQL #variables are applied. These work like in-line programming loop for you and goes for every record in the "PQ" result set. It starts the variables with blank and zero respectively.
Every record compares its dialed number to the last dialed number record (in cases like your 1800 and 1 multiple return sets). If they ARE the same phone, add 1 to the existing #Rank, otherwise, it is a change in phone numbers... always start a phone number change back to rank 1. THEN, it assigns the #lastDst to the phone number it just processed so it can be the basis of the next phone record being tested.
At the end is a HAVING clause to only include those of DialRank = 1
So, per your record set samples, the query would result in records looking something like...
Dial Number Dial_Code Tele2ID Longest DialRank ForNextRowCompare
18006927753 1800 1433 4 1 18006927753 <-- Keep this
18006927753 1 1422 1 2 18006927753
441138973356 441 1024 3 1 441138973356 <-- Keep this
Feedback per comment. TO handle your update, you can just wrap it up
update cdr,
( full query ) as FromThisQuery
where cdr.clean_dst = FromThisQuery.clean_dst
set tele2id = FromThisQuery.tele2id
Please try this query:
select dial_code, clean_dst from cdr c, dialing_codes d where c.clean_dst
like concat(d.dial_code, '%');
You don't need to code all that logic in php. MySQL gives you the functions and comparisons to do it natively in SQL, which is simpler and much more concise.
Hope this helps.

Categories