Accommodating waypoints in a SQL table - mysql

I am currently creating a table to store taxi bookings.
Key
Id - booking id
CustId - id of customer who is being picked up
DriverId - id of driver who is picking up customers
PickupAddr - pickup location
PickupLat - lat coordinate of pickup location
PickupLon - lon coordinate of pickup location
DropoffAdr - drop off location
DropoffLat - lat coordinate of dropoff location
DropoffLon - lon coordinate of dropoff location
Mileage - distance between PickupAddr and DropoffAddr, including any
other stops made
Stops - number of waypoints/stops during journey
Price - what this customer has to pay for this part in the journey
The problem I am facing at the moment is that I don't know how to deal with waypoints.
e.g. if you've been picked up at A to go to B but decide to stop at A1 and A2 during the journey to pick some friends up (all pre-booked beforehand of course)
What would be the best way of restructuring my current table to accommodate this?
Should it come as a separate row or column? As this data is dynamic (i.e. one can't anticipate the number of pickups/dropoffs a customer makes mid journey), what should I be aiming to accomplish.

Since this is a one-to-many relationship, it should be a separate table:
id - Waypoint ID
booking_id - FK to booking table
sequence - ordering of this waypoint within the trip
addr - address of waypoint
lat - latitude of waypoint
long - longitude of waypoint
If you want, you could remove the PickupXXX and DropoffXXX columns from the bookings table, and simply use the waypoints table for this. Pickup could be the first waypoint, and dropoff would be the last one.

Related

MySQL select rows in Geolocation range

Background information: I am making an app(school project) where users can search for an item nearby. My app uses a table of Items where all item data is stored.
I need to get the rows which are in a certain diameter(5km) of my user's current position(51.337036, 4.645095). In the Items table there is column for latitude and longitude to locate the item.
In my current query I can select the rows which are in a square(4 coordinate points) but I need to have a sphere:
WHERE (C.latitude BETWEEN 50 AND 52) AND (C.longitude BETWEEN 3 AND 5)
Is it possible to use a MySQL Geolocation variable or function?
After some research I saw a type POINT, but my table doesn't have that type (the table needs to stay the same).
AS is said in the comment you have to have a point of valid origin
WHERE st_distance_sphere(POINT(-82.337036, 29.645095 ), POINT(C.`longitude`, C.`latitude` ))/1000 <= 2 AND T.difficulty = 1 AND T.terrain = 2;
This would give you all rows that are in max 2 km disance from POINT(-82.337036, 29.645095 )
The you have to put your own location

SQL Group By. Duplicate lat/lng in differents cities

I bought a geo-database a long time ago and I'm updating its precision to the lat/lng values. But I've found some weird stuff. There are some cities that have the same lat/lng coordinates. Thing that is geographically impossible.
id City State Lat Lng
1 A sA XX XX
2 B sA XX XX
3 C sA YY YY
4 D sA ZZ ZZ
So I tried Group By City, Lat, Lng but as I need the id to update the record the group by clause will ask me to add ´id´ column.
From the table ids 1 and 2 should be updated leaving 3 and 4 out. It shouldn't be 2 (or more) cities with the same Lat/Lng. The Table has 22K rows. I could send all to gmap API but I'm looking for use the time, bandwith and hits to the API as smart as possible but I'm running out of time considering I can make a request per second using the free API access.
I've tried
SELECT DISTINCT postcodes_id, Latitude, Longitude, Region1Name, Region2Name, Nation_D
FROM postcodes
where Latitude + Longitude IN
(
SELECT Latitude + Longitude
FROM
(
SELECT postcodes_id, Latitude, Longitude, count(distinct(Region2Name)) as cantidad
FROM postcodes
where Nation_D is not null
GROUP BY Latitude, Longitude
having count(distinct(Region2Name)) > 1
) A
)
AND Nation_D IS NOT NULL
ORDER BY Latitude, Longitude, Region1Name, Region2Name, Nation_D
But is not working as expected. I think its pretty obvious for a new pair of eyes.
I wrote a python script to use Google Map geocode to get the current Lat/Lng and update it if it's different. This script works ok.
Hope someone has an idea. Thanks!!
Running MySQL 5.5 and Python 2.7 on a CentOS 7.
Just some pointers for you, which may be helpful:
You should not use group by or distinct on lat/lon or any combination of them, since they are contiguous floating points numbers and not discrete integers or strings.
By the same token, you should not use WHERE clauses on lat/lon or their sum. If you mean to check for proximity of two locations, use st_distance() function instead.
Multiple city names can refer to the same location. For example, New York, NY and Manhattan, NY.
And a non-technical point: storing Google geocoding data in your database is against their licensing agreement.

Lat/Long Distance Comparison

I am having some trouble with figuring out how to do this. What I have is a list of 160K locations on an Access table with lat and long coordinates for each. I am trying to find out how to create a column that compares 1 item on the list to the rest of the items to bring back the closest distance in miles.
I've figured out how to use the haversine formula to make a 1 to 1 comparison but I am lost in trying to automate the rest.
This is basically what I want to try to produce...
Loc_ID Loc_Lat Loc_Long Min_Miles_Away
1 33.537214 -81.687378 674.48
4 42.16584 -87.845117 11.83
5 41.99558 -87.869057 11.83
6 41.85325 -89.486883 83.75
Explanation to the table...
Location 1 is closest to location 5 (674.48 miles apart)
Location 4 is closest to location 5 (11.83 miles apart)
Location 5 is closest to location 4 (11.83 miles apart)
Location 6 is closest to location 5 (83.75 miles apart)
Any help would be appreciated.
You can do a cartesian join, i.e. a join without a where. It will join each row with every other row. You can do that by simply writing the SQL into the SQL view of the query.
SELECT *
FROM locations a, locations b
Next you can calculate the distance (I guess you have that code already, so just insert the function) on that table.
Finally you can group by MIN.
SELECT loc_id, loc_lat, loc_long, MIN(calulated_distance) as min_miles_away
FROM myCalculatedQuery

how do I design intermittent via points for travel itinerary

I am trying to design the backend and have the following use case.
I have flight information from point A to B and need to define a schema which supports different use cases.
I'm trying to find a good way to handle the case, when there are stopover via points.
For e.g. flight route for A -> B actually looks like this:
A -> C
C -> D
D -> B
so A -> B is one entity, but in turn, it is comprised of several legs.
My current design:
AirLeg table:
- id
- departure and arrival information
- viaPoints: BOOL
viaPoints table:
- id
- airLegId // FK into Airleg table
- similar departure and arrival information from airLeg table
// if viaPoints flag is True in AirLeg table, viaPoints table can be queried for, using airLegId table to retrieve intermediaries.
Is there a better way to deal with this ?
I thought I'll add the info I am storing about a one way trip or segment:
AirLeg-id
Departure Airport : FK into airports
Arrival Airport : FK into airports
Departure timestamp (in departure city's local time)
Arrival timestamp (in arrival city's local time)
flight duration of this airleg: static value
flightId : FK into airlines yielding airline name and flight number
Baggage Policy : text
Misc (TEXT: Cancellation policy)
EDIT:
I added a related question and I think the answer to this problem will have to cater to both the requirements.
If there are multiple segments in a trip, price is defined for the complete trip and not individual segments
Similarly, the price for a round trip is specified as a unit and not individual components from A->B and back, B->A.
I'd design it like this:
Journeys:
- ID
- Other info (billing, whatever)
Segments:
- ID
- JourneyID (FK)
- departure, arrival, etc
And an additional view
Journeys_View
- Journeys.*
- First departure
- Last arrival
I'm trying to piece together the two questions, and it's not totally clear what you want to do - but I think it boils down to the following.
You have an itinerary, which is the parent item. An "itinerary" has multiple legs (question: do you want to deal with multi-part itinerarys, e.g. "London->Paris->New York->London"?). An itinerary has a price. The price is NOT the sum of the price of the legs, because return trips are cheaper than two one ways.
Itinerary
---------
ID
Price
Leg
----
Departure Airport : FK into airports
Arrival Airport : FK into airports
Departure timestamp (in departure city's local time)
Arrival timestamp (in arrival city's local time)
flight duration of this airleg: static value
flightId : FK into airlines yielding airline name and flight number
Baggage Policy : text
Misc (TEXT: Cancellation policy)
You could store price in a separate table - but you only need to do this if price changes independently of itinerary (e.g. if the price on Monday is $100, and on Tuesday it's $200).
I would encourage you not to use "magic numbers" in your database schema - instead of having the return leg be "-1", you should leave it NULL - there is no return leg. This makes your SQL a lot easier to read, and far less error prone - you don't depend on developers remembering that "-1" means there's no return leg, -2 meaning there's a provisionally booked leg etc.

select places with nearly same location (duplicates) by latitude/longitude

Lets say I have a table venues with following columns:
id
user_id
name
latitude
longitude
The latitude and longitude are kept as FLOAT(10,6) values. As different users add venues, there are venue duplicates. How can I select all the duplicates from the table in range up to lets say 50 metres (as it might be hard to achieve as the longitudial meter equivalents are different at different latitudes, so this is absolutely aproximate)? The query should select all venues: VenueA and VenueB (there might be VenueC, VenueD, etc) so that I can compare them. It should filter out venues that are actually one per location in the range (I care only for duplicates).
I was looking for an answer but had to settle with answering myself.
SELECT s1.id, s1.name, s2.id, s2.name FROM venues s1, venues s2
WHERE s2.id > s1.id AND
(POW(s1.latitude - s2.latitude, 2) + POW(s1.longitude - s2.longitude, 2) < 0.001)
The first condition is to select only half of matrix as order of similar venues is not important. The second one is simplified distance calculator. As user185631 suggested haversine formula should do the trick if you need more precision but I didn't need it as I was looking for duplicates with the same coordinates but couldn't settle with s1.latitude = s2.latitude AND s1.longitude = s2.longitude due to float/decimal corruption in my DB.
Of course checking this at insert would be better but if you get corrupt DB you need to clean it somehow. Please also note that this query is heavy on server if your tables are big.
Create a function which computes distances between lat/lons. For small/less accurate distance (which is the case here) you can use the Equirectangular approximation (see section here: http://www.movable-type.co.uk/scripts/latlong.html). If the distance is less than your chosen threshold (50m), then it is a duplicate.
Determine what 50 meters is in terms of lat and long. Then plus and minus that to your starting location to come up with a max and min for both lat and long. Then...
SELECT id FROM venues WHERE latitude < (your max latitude) AND latitude > (your min latitude) AND longitude < (your max longitude) AND longitude > (your min longitude);
Converting meters to lat/long is very tricky as it depends on where the starting point is on the globe. See the middle section of the page here: http://www.uwgb.edu/dutchs/usefuldata/utmformulas.htm