Compare a date with a block of dates in SQL - sql

i tried to ready a lot of date comparisons that i found here on stackoverflow and spread into the internet but i wasn't able to find the solution.
I have the following table (Trips):
VehicleID DriverID xID CheckIn CheckOut DateHour
462 257 7 1 0 16/12/2017 20:40:00
462 257 7 0 1 19/12/2017 10:05:00
5032 3746 11 1 0 02/10/2017 07:00:00
5032 3746 11 0 1 06/10/2017 17:00:00
When my company receives a traffic ticket, i want to compare the date from the ticket with the hole block of dates from the table "Trips", each block starts with CheckIn = 1 and finishes with CheckOut = 1, so this way i will know which driver was responsable for the ticket through the DriverID.
For example: the traffic ticket date and time are: 17/12/2017 08:00:00 and the Vehicle is the one with id = 462, i'll insert this date and time in a field in our system to consult automaticaly which driver was driving that car at that moment, we won´t use the ticket table yet. Looking at my example, i know it should return DriverID = 257, but theres a lot of trips with the same vehicle and diferent drivers.....The major problem is how can i compare the Date and Hour from the Ticket with the range of dates from the trips, since i have to consider 1 trip = 2 lines in the table
Unfortunately i can't change the way this table was created, cause we need this 2 lines, CheckIn and CheckOut, separately.
Any thoughts or directions?
Thank you for your attention

select t1.VehicleID
,t1.DriverID
,t1.xID
,t1.DateHour as Checkin
,t2.DateHour as Checkout
from trips as t1 join trips as t2 --self join trips to get both start and end in a single row
on t1.VehicleID = t2.VehicleID -- add all columns
and t1.DriverID = t2.DriverID -- which define
and t1.xID = t2.xID -- a unique trip
and t1.Checkin = 1 -- start
and t2.Checkout = 1 -- end
join tickets -- now join tickets
on tickets.trafficDateHour between t1.DateHour and t2.DateHour

I didn't make sample tables, this will not run as is, but something like this should do it for you:
SELECT *
FROM tickets, trips
WHERE
trips.datehour in (
SELECT trips.datehour
FROM tickets, trips
WHERE
tickets.ticket_date < trips.datehour AND
trips.checkin = 0
) AND
tickets.ticket_date > trips.datehour AND
trips.checkin = 1
If you are running this for a specific date as described in the comment above, it will work. If you are trying to run it for a set of ticket dates all at once, you'll require recursion. Recursion is a different beast depending on your flavor of SQL.

Related

Increasing the 'stop-time' of generated routes

I'm learning some basic SQL skills and I was toying around with some data to see what I can do, however, I'm a bit stuck on how to proceed with my current problem.
I have a table that looks like this:
RouteID
SegmentID
Order
BeginTime
EndTime
CarID
1
45
1
10:00:30
10:01:00
1
1
46
2
10:01:00
10:01:30
1
1
47
3
10:01:30
10:02:00
1
2
50
1
10:05:00
10:05:30
1
2
49
2
10:06:00
10:06:30
1
3
900
1
20:01:00
20:01:30
2
As you can see, we have a bunch of cars and the routes they have driven. A route is simply a sequence of traveled roadsegments. Furthermore, we have the timestamps of entering the segments and leaving the segments.
The goal
What I want to do is to create an easy origin-destination analysis. I'm given a list of segments that belong to location A and similarly, I'm given a list of segments belonging to location B.
My solution
Alright, this is easy. I have made a new table that for each route lists the first and last segment. Using this table, it is then super easy to get the answer.
The problem
The routes themselves are not generated as they should be. In the above table for example, you'll see that car 1 has two routes. The first route end at 10:02:00 whereas the second route begins at 10:05:00. As the this time difference is less that 5 minutes apart, I'd very much like to consider this as 'one route'. I'm not necessarily interested in generating a new table where we glue all routes of the same car together provided that they lie within 5 minutes of each other (although, I'd be very interested in the type of queries one would have to write to accomplish this).
For now, I'd be very happy to get a clue/answer on how to somehow glue these routes together and to make a table where the origin and destination of each route is listed and routes of the same car with at most 5 minutes in between are considered as one route.
I thank you in advance. Although I had some close attempts, a proper solution seems beyond my current (very basic) SQL-skills.
You can compare ordered rows to flag a new route start for a car. And next get a virtual route number within a car. For example
select routeID, SegmentID, [Order], BeginTime, EndTime, CarID,
-- virtual route nbr within a car
sum(newRouteFlag) over(partition by CarID order by BeginTime) rtNmbr
from (
select routeID, SegmentID, [Order], BeginTime, EndTime, CarID,
case when lag(routeID) over(partition by CarID order by BeginTime) = routeID
or dateadd(minute, 5, lag(BeginTime) over(partition by CarID order by BeginTime)) >= BeginTime then 0 else 1 end newRouteFlag
from tbl
) t

Create column based on grouping other values

I have difficulties formulating my issue.
I have a view which brings these results. There's a need to add a column to the view, which will pair up round-trip flights with identical number.
Flt_No From_Airport To_Airport Dep_Date RequiredResult
124 |LCA |CDG |10/19/14 5:00 1
125 |CDG |LCA |10/19/14 10:00 1
197 |LCA |BCN |10/4/12 5:00 2
198 |BCN |LCA |10/4/12 11:00 2
501 |LCA |HER |15/8/12 12:05 3
502 |HER |LCA |15/8/12 15:15 3
I.e. flight 124 is going from Larnaca to CDG, and flight 125 is going back from CDG to Larnaca - they both have to have the same identifier.
Round-trip flights will always have following flight numbers.
I have a bunch of conditions which I won't write now.
Omitting hours is not an option, they're important.
I was thinking dense_rank() but I don't know how to create one identifier for 2 flights with different numbers, please help.
If your data is similar to the sample data posted, then the following query should give the required result:
SELECT *,
DENSE_RANK() OVER (ORDER BY CASE
WHEN From_Airport < To_Airport THEN From_Airport
ELSE To_Airport
END)
FROM mytable
Join conditions are not limited to simple equality. Assuming {Flight No, Departure, Destination} is unique on any one day, then a self join should do it:
select whatever
from flights outbound
inner join flights inbound on outbound.flt_no+1 = inbound.flt_no
and cast(outbound.dep_date, date)
= cast(inbound.dep_date, date)
and outbound.From_Airport = inbound.To_Airport
and outbound.To_Airpott = inbound.From_Ariport

Access SQL Conditional Clause Multiple Conditions/Records Same Column

I've run into a problem trying to write some SQL for MS Access that will parse some of the data down in the way I was hoping. While I'm admittedly new (or still learning beyond the bounds of a college class I took five years ago) with regards to SQL, I'd like to think what I'm trying to do can be accomplished.
The scenario:
While I might not have started this all of that efficient to start with, I began with two tables. The original dataset started with a little under 72k records.
The goal, or what I was seeking to accomplish in the case was to find all of the records where someone appeared for more than one Charge, and the outcome for a charge that is defined as having 0 points is guilty, however the other charges are found either NG or Dismissed.
Here is what I have so far. That data I started with came from two tables, one which contained the appearances, one that had the codes and points.
An example for the appearances would be similar to the following:
APP DATE CHARGE OUTCOME
===================================
1 1/1/2014 137 GT
2 1/5/2014 122 GT
2 1/5/2014 123 DI
3 1/6/2014 257 DI
3 1/6/2014 257 DI
4 1/6/2014 137 NG
4 1/6/2014 123 DI
4 1/6/2014 122 GT
I had a second table which linked the charge, to the potential number of points associated with the charge, fairly simple formatting there
CHARGE POINT
===============
122 0
123 2
137 2
257 0
So I created a few basic queries, since I'm largely filling in the blanks based on a bulk data file that was provided to me. The first one pulled joined the first two tables together, so I was left with a table that looked something along the lines of:
APP DATE CHARGE OUTCOME POINTS
==========================================
1 1/1/2014 137 GT 2
2 1/5/2014 122 GT 0
2 1/5/2014 123 DI 2
3 1/6/2014 257 DI 0
3 1/6/2014 257 DI 0
4 1/6/2014 137 NG 2
4 1/6/2014 123 DI 2
4 1/6/2014 122 GT 0
I then created three small queries that were each asked to produce a subset of data from the main query, one for OUTCOME=GT, Points=0, another for Outcome=NG, Points>2, the last Outcome=DI, Points>2. Each one of the queries was called in a make table query that brought the record set down from the original 72k to 39k. Applying yet another query with
Select * from record_set Where RecordID IN
(Select RecordID from record_Set
GROUP BY RecordID
HAVING COUNT (*) > 1))
on the end brought the total down to just under 21k.
My problem is this:
The dataset I would like to return needs to further filter the results. Currently I haven't figured out how to weed out the APP values where both values are 0. For all I know I should have approached this a completely different way.
EDIT:
What I would be looking for is the dataset that returns to look something like this:
APP DATE CHARGE OUTCOME POINTS
==========================================
2 1/5/2014 122 GT 0
2 1/5/2014 123 DI 2
4 1/6/2014 137 NG 2
4 1/6/2014 123 DI 2
4 1/6/2014 122 GT 0
Where the single record was pulled, and the APP where the OUTCOME was DI/0 for all the Charges involved.
The current attempts I have tried using a straight forward WHERE clause only evaluate the records single value. I guess I'm looking for a way to evaluate both. Maybe that would be easier if I wrote the value to separate temp tables and then did a union only for the APP values that appeared in both tables?
Any help or guidance would be greatly appreciated!
My MS-Access experience is rather close to zero, but I believe this syntax will work. At least it might spark some ideas.
SELECT APP, DATE, CHARGE, OUTCOME, POINTS
FROM APP A
INNER JOIN CHARGE C on C.Charge = A.Charge
WHERE (Outcome = 'GT' and Points = '0')
OR (Outcome = 'NG' and Points > '2')
OR (Outcome = 'DI' and Points > '2')
I'm not sure what you mean by cases when both values are 0, but more than likely you can add another WHERE clause to filter those out as well.
EDIT:
I guess the data set I am seeking will always have the following: More
than one APP, while containing one record with 0 PTS that was a GT,
and one (or more records) that can be a point value greater than 0
that is either DI or NG. The reason I started at 2 is that I know
there aren't any values that contain a 1, but I guess to be thorough
they could be included
First get APPs that meet the 0 PT and GT requirements:
SELECT APP
FROM APP A
INNER JOIN CHARGE C on C.Charge = A.Charge
WHERE Outcome = 'GT'
AND Points = '0'
Reuse above to get APPs that have point values greater than 0 and DI or NG:
SELECT APP
FROM APP A
INNER JOIN CHARGE C on C.Charge = A.Charge
WHERE (Outcome = 'DI' AND Points > '0')
OR (Outcome = 'NG' AND Points > '0')
Next, combine the above logic into one query, using two subqueries, in order to only pull APP data that meets both requirements:
SELECT APP, DATE, A.CHARGE, OUTCOME, POINTS
FROM APP A
INNER JOIN CHARGE C on C.Charge = A.Charge
WHERE APP IN (
SELECT APP
FROM APP A
INNER JOIN CHARGE C on C.Charge = A.Charge
WHERE Outcome = 'GT'
AND Points = '0'
)
AND APP IN (
SELECT APP
FROM APP A
INNER JOIN CHARGE C on C.Charge = A.Charge
WHERE (Outcome = 'NG' AND Points > '0')
OR (Outcome = 'DI' AND Points > '0')
)
This will result in only APPs that have a GT, 0 PT charge, AND another charge that is DI or NG with 1 or greater PTs.

sql query condition in oracle report IF ELSE

I have The following tables:
DOCUMENT(iddoc,doctype,title,publishingdate,validTillDate)
USERS(iduser,fname,lname)
TRANSACTION(idtrans,iduser,iddoc,transdate,schedulereturndate)
I'm asked to Indicate for a given document whether it is available or not and if it is borrowed by whom, and when it should be returned. So how can i have these conditions in my query.
where my code will be like this:
if(d.validTillDate < SYSDATE){
SELECT u.iduser t.schedulereturndate
FROM USERS u, TRANSACTION t
WHERE u.iduser=t.iduser
}
SO I WANNA KNOW HOW CAN I CODE THIS IF
The query for a borrowed document would be something like this:
SELECT d.iddoc,u.iduser t.schedulereturndate,'Borrowed'
from document d,
,USERS u
,TRANSACTION t
WHERE u.iduser=t.iduser
and t.iddoc=d.iddoc
and d.validitydate<sysdate
union
SELECT d.iddoc,null,null,'Not borrowed'
from document d,
WHERE d.validitydate is null
or d.validitydate>=sysdate
Edit ) added a union for the not borrowed documents.
It's hard to understand your question for me.
If I guessed right, then:
SELECT d.iddoc, u.iduser, t.schedulereturndate
FROM
document d
LEFT JOIN transaction t ON
(d.iddoc=t.iddoc)
-- join by iddoc field
AND (SYSDATE BETWEEN t.transdate AND t.schedulereturndate)
-- I assume we need only current transactions, not past (or future?)
WHERE
(SYSDATE<=d.validTillDate)
-- I assume we need only documents whose validity date not passed yet
Assuming there are no active transactions for iddoc=1, one active transaction for iddoc=2 and two active transactions for iddoc=3, the result will look like:
iddoc | iduser | schedulereturndate
------+--------+-------------------
1 NULL NULL
2 534 2017-09-08
3 54334 2016-03-02
3 2433 2016-07-01

How can I group flight legs together into routes for counting?

I have a person's flight history and want to find their most frequent route. All flights are stored as a single row in a table, even return trips where a->b will be in one row and b->a will be in another.
I need to identify where two legs equate to a route; for example:
This person has flown 16 times in total
New York to Paris 2 times (Flight key: JFKCDG)
Paris to New York 2 times (Flight Key: CDGJFK)
New York to London 3 times (Flight Key: JFKLHR)
Currently I don't know a way to group the first two above as a 'Route' and therefore any query I write considers JFKLHR to be the most frequent route (6 times between NY and London) even though I can see from the data that this person has flown between NY and Paris a total of 10 times
Sample Table:
User ID¦Flight Key
-------------------
1 ¦JFKCDG
1 ¦JFKCDG
1 ¦CDGJFK
1 ¦CDGJFK
1 ¦JFKLHR
1 ¦JFKLHR
1 ¦JFKLHR
Expected Output
User ID¦Flight Key¦Count
------------------------
1 ¦JFKCDGJFK ¦4
Building on the clever idea in the answer by #fancyPants. You can use string functions to compare each leg of a route and patch together a full return trip.
I believe this query should work. The first part of the common table expression turns those flights that are round trips into three parts (src-dst-src) and the second part returns those that are one way (as src-dst).
with flights_cte as (
select
USERID,
case when left(flightkey,3) > right(flightkey,3)
then concat(flightkey, left(flightkey,3))
else concat(right(flightkey,3), flightkey)
end as flightkey,
count(*) count
from flights f
where exists (
select 1 from flights where right(f.flightkey,3) = left(flightKey,3)
)
group by
userid,
case
when left(flightkey,3) > right(flightkey,3)
then concat(flightkey, left(flightkey,3))
else concat(right(flightkey,3), flightkey)
end
union all
select userid, FlightKey, count(*)
from flights f
where not exists (
select 1 from flights where right(f.flightkey,3) = left(flightKey,3)
)
group by UserID, FlightKey
)
select flights_cte.userid, flights_cte.flightkey, flights_cte.count
from flights_cte
join (select userid, max(count) _max_count from flights_cte group by userid) _max
on flights_cte.UserID=_max.UserID and flights_cte.count = _max_count
A sample SQL Fiddle gives this output:
| USERID | FLIGHTKEY | COUNT |
|--------|-----------|-------|
| 1 | JFKCDGJFK | 4 |
Assuming routes are not a single row, otherwise you wouldn't be asking.. (although I would guess that the whole route is in some other table, maybe reservation-related)
Guessing the first step is to group this data by person and flights that compose a 'route'. I have an article called T-SQL: Identify bad dates in a time series where the time series can be modified to detect gaps between legs of over a day (guess) to differentiate routes. Second step would be to convert legs into route, i.e. JFK-CDG and CDG-JFK to single value JFK-CDG-JFK.
Then it would be a single query, counting the above single value route, and ORDER BY that count.
Good luck.