SQL Adjustment to query for selecting specfic times - sql

I have the following query below to select points from a database. I need to make one slight adjustment, I only want points from '2013-09'. I have tried by simply adding AND "Time" LIKE '2013-09%' but that doesn't seem to work as it produces 0 records. I also know for a fact that the database contains records matching this year, as I have used the query below (with the time selection part removed) to select all the records . What might be the issue?
; WITH positions AS (
SELECT MMSI
, Message_ID
, "Time"
, Latitude
, Longitude
FROM dbo.DecodedCSVMessages_Staging
WHERE Message_ID IN (1, 3)
AND Latitude > 45
AND Latitude < 85
AND Longitude < -50
AND Longitude > -141
AND "Time" LIKE '2013-09%' <- this is where I'd put it
)
, details AS (
SELECT MMSI
, Ship_Type
, Vessel_Name
, IMO
, Row_Number() OVER (PARTITION BY MMSI ORDER BY "Time" DESC) As row_num
FROM dbo.DecodedCSVMessages_Staging
WHERE Message_ID = 5
)
SELECT positions.MMSI
, positions.Message_ID
, positions."Time"
, details.Ship_Type
, details.Vessel_Name
, details.IMO
, positions.Latitude
, positions.Longitude
FROM positions
INNER
JOIN details
ON details.MMSI = positions.MMSI

There is no reason to use LIKE, change this line to:
AND [Time] > '2013-09-01'

If you only want values from September 2013 you can try this:
AND "Time" >= '2013-09-01'
AND "Time" < '2013-10-01'

Related

Calculate time span between two specific statuses on the database for each ID

I have a table on the database that contains statuses updated on each vehicle I have, I want to calculate how many days each vehicle spends time between two specific statuses 'Maintenance' and 'Read'.
My table looks something like this
and I want to result to be like this, only show the number of days a vehicle spends in maintenance before becoming ready on a specific day
The code I written looks like this
drop table if exists #temps1
select
VehicleId,
json_value(VehiclesHistoryStatusID.text,'$.en') as VehiclesHistoryStatus,
VehiclesHistory.CreationTime,
datediff(day, VehiclesHistory.CreationTime ,
lead(VehiclesHistory.CreationTime ) over (order by VehiclesHistory.CreationTime ) ) as days,
lag(json_value(VehiclesHistoryStatusID.text,'$.en')) over (order by VehiclesHistory.CreationTime) as PrevStatus,
case
when (lag(json_value(VehiclesHistoryStatusID.text,'$.en')) over (order by VehiclesHistory.CreationTime) <> json_value(VehiclesHistoryStatusID.text,'$.en')) THEN datediff(day, VehiclesHistory.CreationTime , (lag(VehiclesHistory.CreationTime ) over (order by VehiclesHistory.CreationTime ))) else 0 end as testing
into #temps1
from fleet.VehicleHistory VehiclesHistory
left join Fleet.Lookups as VehiclesHistoryStatusID on VehiclesHistoryStatusID.Id = VehiclesHistory.StatusId
where (year(VehiclesHistory.CreationTime) > 2021 and (VehiclesHistory.StatusId = 140 Or VehiclesHistory.StatusId = 144) )
group by VehiclesHistory.VehicleId ,VehiclesHistory.CreationTime , VehiclesHistoryStatusID.text
order by VehicleId desc
drop table if exists #temps2
select * into #temps2 from #temps1 where testing <> 0
select * from #temps2
Try this
SELECT innerQ.VehichleID,innerQ.CreationDate,innerQ.Status
,SUM(DATEDIFF(DAY,innerQ.PrevMaintenance,innerQ.CreationDate)) AS DayDuration
FROM
(
SELECT t1.VehichleID,t1.CreationDate,t1.Status,
(SELECT top(1) t2.CreationDate FROM dbo.Test t2
WHERE t1.VehichleID=t2.VehichleID
AND t2.CreationDate<t1.CreationDate
AND t2.Status='Maintenance'
ORDER BY t2.CreationDate Desc) AS PrevMaintenance
FROM
dbo.Test t1 WHERE t1.Status='Ready'
) innerQ
WHERE innerQ.PrevMaintenance IS NOT NULL
GROUP BY innerQ.VehichleID,innerQ.CreationDate,innerQ.Status
In this query first we are finding the most recent 'maintenance' date before each 'ready' date in the inner most query (if exists). Then calculate the time span with DATEDIFF and sum all this spans for each vehicle.

T-SQL query to fetch row with multiple aggregate functions

I have the following problem. I need to fetch the row for each distinct user_id with the min rank, max end date, max begin date, and max sequence number in that order. Essentially, I want a user's highest ranked, most recent MAJOR_ID. I am trying to avoid making separate temp tables and joining on those aggregate functions like the following:
select USER_ID
, SEQ_NBR
, BEGIN_DATE
, END_DATE
, MAJOR_RANK
, MAJOR_ID
, DEGREE_CODE
into #major0
from majors
select USER_ID
, MIN(MAJOR_RANK) as MAJOR_RANK
into #major1
from #major0
group by USER_ID
select #major0.USER_ID
, #major0.MAJOR_RANK
, MAX(#major0.END_DATE) as END_DATE
into #major2
from #major0
inner join #major1 on #major0.USER_ID = #major1.USER_ID and #major0.MAJOR_RANK = #major1.MAJOR_RANK
group by #major0.USER_ID
, #major0.MAJOR_RANK
etc...
until I get to that row that satisfies all the criteria, and I join back on all the fields from the original query. Does that make sense? It's a lot of work to write this out, and I can't create a view of it unless I made a absurdly long set of subqueries, I don't think I can utilize MIN(MAJOR_RANK) OVER (PARTITION BY USER_ID) in a subquery for all these fields because I will lose records that don't satisfy all of them.
Any suggestions would help! Thank you!
I do not see what the sequence_number is, but you can most likely solve this using a common table expression with row_number()
;with cte as (
select
user_id
, begin_date
, end_date
, major_rank
, major_id
, degree_code
, rn = row_number() over (
partition by user_id
order by major_rank asc, end_date desc, begin_date desc /*, sequence_number? desc*/
)
from majors
)
select
user_id
, begin_date
, end_date
, major_rank
, major_id
, degree_code
from cte
where rn = 1
without the cte
select
user_id
, begin_date
, end_date
, major_rank
, major_id
, degree_code
from (
select
user_id
, begin_date
, end_date
, major_rank
, major_id
, degree_code
, rn = row_number() over (
partition by user_id
order by major_rank asc, end_date desc, begin_date desc /*, sequence_number? desc*/
)
from majors
) sub
where rn = 1

MIN MAX query with a twist

I need to get the MIN and MAX dates for volume but I need to group it based on volume and not all the volume of same amount....
Basically, I have daily volume and dates for those daily volume. I need to be able to get the MIN Date as "to" and MAX date as "from" for a set of volume.
Note that the volume can traverse dates and then break and then have a new set of dates for the same volume.
Hopefully the screenshots below do a better job explaining than I can. I know how to do this via code.. but was wondering if the same was possible with SQL.
Please note that the SQL will be called from within an application and I can't insert into a temp table to get my end result data set...
Here is the raw data that I am querying using select *:
Here is what I ultimately want:
The query that I am running gives me the MIN and MAX for all the occurrences of the volume 1100. I want it split based on the break between dates as shown in the End result screenshot....
Here is my SQL:
SELECT daily_volume, MIN(volume_date) AS min_date, MAX(volume_date) AS max_date, ins_num
FROM daily_volume
WHERE ins_num = 3854439
GROUP BY daily_volume, ins_num
The following was written for sql server, but it should work for other databases (sqlfiddle):
with DatesMinMax as
(
select
volume_date,
daily_volume,
isnull
(
(
select top 1 d2.volume_date
from daily_volume d2
where d.volume_date > d2.volume_date and d.daily_volume <> d2.daily_volume
order by d2.volume_date desc
)
, '1753-01-01'
) as min_date,
isnull
(
(
select top 1 d2.volume_date
from daily_volume d2
where d.volume_date < d2.volume_date and d.daily_volume <> d2.daily_volume
order by d2.volume_date
)
, '9999-12-31'
) as max_date
from daily_volume d
),
DatesFromTo as
(
select d1.daily_volume as qty,
(select min(d2.volume_date)
from DatesMinMax d2
where d2.volume_date > d1.min_date and d2.volume_date < d1.max_date
) as [from],
(select max(d2.volume_date)
from DatesMinMax d2
where d2.volume_date > d1.min_date and d2.volume_date < d1.max_date
) as [to]
from DatesMinMax d1
)
select distinct
qty,
[from],
[to]
from DatesFromTo
order by [from]
DatesMinMax is used to get the first date that had a different volume than the current volume
DatesFromTo is used to get the date range for each row

How can I include in schedules today's departures after midnight using GTFS?

I began with GTFS and offhand ran into big problem with my SQL query:
SELECT *, ( some columns AS shortcuts )
FROM stop_times
LEFT JOIN trips ON stop_times.trip_id = trips.trip_id
WHERE trips.max_sequence != stop_times.stop_sequence
AND stop_id IN( $incodes )
AND trips.service_id IN ( $service_ids )
AND ( departure_time >= $time )
AND ( trips.end_time >= $time )
AND ( trips.start_time <= $time_plus_3hrs )
GROUP BY t,l,sm
ORDER BY t ASC, l DESC
LIMIT 14
This should show departures from some stop in next 3 hours.
It works but with approaching midnight (e.g. 23:50) it catch only "today's departure". After midnight it catch only "new day departures" and departures from previous day are missing, because they have departure_time e.g. "24:05" (=not bigger than $time 00:05).
Is possible to use something lighter than UNION same query for next day?
If UNION is using, how can I ORDER departures for trimming by LIMIT?
Trips.start_time and end_time are my auxiliary variables for accelerate SQL query execution, it means sequence1-arrival_time and MAXsequence-departure_time of any trip.
Using UNION to link together a query for each day is going to be your best bet, unless perhaps you want to issue two completely separate queries and then merge the results together in your application. The contortionism required to do all this with a single SELECT statement (assuming it's even possible) would not be worth the effort.
Part of the complexity here is that the set of active service IDs can vary between consecutive days, so a distinct set must be used for each one. (For a suggestion of how to build this set in SQL using a subquery and table join, see my answer to "How do I use calendar exceptions to generate accurate schedules using GTFS?".)
More complexity arises from the fact the results for each day must be treated differently: For the result set to be ordered correctly, we need to subtract twenty-four hours from all of (and only) yesterday's times.
Try a query like this, following the "pseudo-SQL" in your question and assuming you are using MySQL/MariaDB:
SELECT *, SUBTIME(departure_time, '24:00:00') AS t, ...
FROM stop_times
LEFT JOIN trips ON stop_times.trip_id = trips.trip_id
WHERE trips.max_sequence != stop_times.stop_sequence
AND stop_id IN ( $incodes )
AND trips.service_id IN ( $yesterdays_service_ids )
AND ( departure_time >= ADDTIME($time, '24:00:00') )
AND ( trips.end_time >= ADDTIME($time, '24:00:00') )
AND ( trips.start_time <= ADDTIME($time_plus_3hrs, '24:00:00') )
UNION
SELECT *, departure_time AS t, ...
FROM stop_times
LEFT JOIN trips ON stop_times.trip_id = trips.trip_id
WHERE trips.max_sequence != stop_times.stop_sequence
AND stop_id IN ( $incodes )
AND trips.service_id IN ( $todays_service_ids )
AND ( departure_time >= $time )
AND ( trips.end_time >= $time )
AND ( trips.start_time <= $time_plus_3hrs )
GROUP BY t, l, sm
ORDER BY t ASC, l DESC
LIMIT 14

What can I do to speed up this SQL Query?

Here is some detail, I tried to make a SQLFiddle but I kept getting errors with my variables. This works in Sql Server 2008. My question is, how can I make my query faster? I know I'm doing a number of things wrong here (repeated nester queries), I'm hoping to get someone to take a look and help me get this down from its 30 minute execution time! :-S
The basic idea behind the query is that in the game I want to find all players which haven't moved 5 units for a period of time, who have fired whilst stood still and did not fire for 60 minutes before they stopped moving.
The query works, but it's the AND NOT EXISTS clause which is slowing things down to a crawl, before I added that it took 16 seconds to run! 16 seconds is still a long time, so any other improvements would be appreciated, but for now with this being my own POC game (just throwing bits and pieces together), 16 seconds is acceptable...
DECLARE #n INT , #DistanceLimit INT
SELECT #n = 2 , #DistanceLimit = 5;
WITH partitioned
AS ( SELECT * ,
CASE WHEN Distance < #DistanceLimit THEN 1
ELSE 0
END AS PartitionID
FROM EntityStateEvent
WHERE ExerciseID = '8B50D860-6C4E-11E1-8E70-0025648E65EC'
),
sequenced
AS ( SELECT ROW_NUMBER() OVER ( PARTITION BY PlayerID ORDER BY EventTime ) AS MasterSeqID ,
ROW_NUMBER() OVER ( PARTITION BY PlayerID, PartitionID ORDER BY EventTime ) AS PartIDSeqID ,
*
FROM partitioned
),
filter
AS ( SELECT MasterSeqID - PartIDSeqID AS GroupID ,
MIN(MasterSeqID) AS GroupFirstMastSeqID ,
MAX(MasterSeqID) AS GroupFinalMastSeqID ,
PlayerID
FROM sequenced
WHERE PartitionID = 1
GROUP BY PlayerID ,
MasterSeqID - PartIDSeqID
HAVING COUNT(*) >= #n
)
SELECT
DISTINCT ( sequenced.PlayerID ) ,
MIN(sequenced.EventTime) AS StartTime ,
MAX(sequenced.EventTime) AS EndTime ,
DATEDIFF(minute, MIN(sequenced.EventTime),
MAX(sequenced.EventTime)) AS StaticTime ,
Player.Designation AS 'Player'
FROM filter
INNER JOIN sequenced ON sequenced.PlayerID = filter.PlayerID
AND sequenced.MasterSeqID >= filter.GroupFirstMastSeqID
AND sequenced.MasterSeqID <= filter.GroupFinalMastSeqID
INNER JOIN Events ON Events.FiringPlayerID = sequenced.PlayerID
INNER JOIN Player ON Player.PlayerID = sequenced.PlayerID
AND Player.Force = 'FR'
AND NOT EXISTS ( SELECT *
FROM Events
WHERE Events.FiringPlayerID = Player.PlayerID
GROUP BY Events.FiringTime
HAVING Events.FiringTime BETWEEN DATEADD(minute,
-60,
( SELECT
MIN(s.EventTime)
FROM
sequenced s
WHERE
s.PlayerID = filter.PlayerID
AND s.MasterSeqID >= filter.GroupFirstMastSeqID
AND s.MasterSeqID <= filter.GroupFinalMastSeqID
))
AND
( SELECT
MIN(s.EventTime)
FROM
sequenced s
WHERE
s.PlayerID = filter.PlayerID
AND s.MasterSeqID >= filter.GroupFirstMastSeqID
AND s.MasterSeqID <= filter.GroupFinalMastSeqID
) )
INNER JOIN Player HitPlayer ON HitPlayer.PlayerID = Events.HitPlayerID
WHERE HitPlayer.[FORCE] = 'HO'
GROUP BY GroupID ,
sequenced.PlayerID ,
Events.FiringPlayerID ,
Events.FiringTime ,
Player.Designation
HAVING DATEDIFF(minute, MIN(sequenced.EventTime),
MAX(sequenced.EventTime)) > 5
AND Events.FiringTime BETWEEN MIN(sequenced.EventTime)
AND MAX(sequenced.EventTime)
ORDER BY StartTime
The first thing I'd do is materialize the sequenced CTE, since it is used 4 times in the overall schema of things.
This would mean moving around some code and using #temp tables in place of the sequential CTEs. It would also work out an order of magnitude better since you can cluster #temp tables and create useful indexes for the JOINs.
See this SQLFiddle that shows that CTEs can be evaluated many times, once for each reference.