I've imported US Census Shapefiles (All Roads) into SQL Serve 2008 R2. I'd like to find out what "road" a particular lat/long coordinates fall on. What does that query look like?
I'm new to GIS; searched around without luck. Thanks!
Here are the top 10 rows as a sample data set:
MULTILINESTRING ((-73.924385 40.865365, -73.92249799999999 40.866064, -73.920611999999991 40.866758999999995, -73.919215 40.867275, -73.918414 40.867584), (-73.92662 40.864525, -73.924385 40.865365))
LINESTRING (-73.91434 40.862521, -73.915523999999991 40.863040999999996, -73.917063 40.863690999999996, -73.918943 40.864463, -73.919361999999992 40.864809, -73.919996 40.865797, -73.920611999999991 40.866758999999995, -73.921213999999992 40.867692999999996, -73.921725999999992 40.868497, -73.922145 40.86915, -73.922343 40.869459)
LINESTRING (-73.91704399999999 40.867025999999996, -73.918414 40.867584, -73.919754 40.868114)
LINESTRING (-73.91911 40.859573, -73.919845999999993 40.859898, -73.921235 40.860476)
LINESTRING (-73.917913 40.869667, -73.918109 40.86987, -73.918269999999993 40.870035, -73.918643 40.870421, -73.919249999999991 40.871010999999996, -73.919671 40.872076)
LINESTRING (-73.917913 40.869667, -73.918109 40.86987, -73.918269999999993 40.870035, -73.918643 40.870421, -73.919249999999991 40.871010999999996, -73.919671 40.872076)
LINESTRING (-73.911771 40.868096, -73.913352 40.868777, -73.915183 40.869551, -73.91588 40.869847)
LINESTRING (-73.911227 40.871655, -73.91268 40.872292)
LINESTRING (-73.911227 40.871655, -73.91268 40.872292)
LINESTRING (-73.932523 40.854538, -73.932092 40.855157, -73.931654999999992 40.855754999999995, -73.929509 40.857341999999996)
The following returns the closest road to the search point specified. It was kinda slow until we added spatial indexes to the roads table.
DECLARE #search_point GEOGRAPHY, #search_buffer_metres INT = 50
SET #search_point = geography::STGeomFromText( 'POINT(174.083058 -35.410539)',4326 )
SELECT TOP 1
ROAD_NAME,SHAPE.STDistance( #search_point ) AS MetresFromSearchPoint
FROM
ROADS
WHERE
SHAPE.STIntersects( #search_point.STBuffer(#search_buffer_metres) ) = 1
ORDER BY
SHAPE.STDistance( #search_point )
This is a non-trivial problem, and probably won't get you a satisfactory answer here. The problem with trying to resolve the street of a house with the tiger data is that there isn't really enough information to make a good deterministic decision- all that the tiger files provide is the geographic coordinates for each end of a road segment, along with the name of the road and a few other bits of information.
My house is a great example of why this is difficult. The property is bounded by a residential road, a tertiary road, and an interstate highway. My house is set far back on the lot, and so the rooftop lat/lon is geographically closer to the highway than either of the other two roads. My address of course is on the residential street, but there is no way you'd be able to determine that from the data that you have.
Related
I would like to compute the shortest distance from the yellow point in the image below to the polygon boundary using built in BigQuery Geo functions.
I could not find anything myself.
Here is the query that builds the example.
WITH objects AS(
SELECT 'POLYGON((-84.3043408314983 33.78004925, -84.3058929975152 33.7780287948446, -84.3026549053438 33.77962155, -84.3018234603607 33.7798783, -84.3041030408163 33.7785105714286, -84.2983655895464 33.7814847396304, -84.2869801170094 33.7772419185107, -84.2842584693878 33.7827876938775, -84.2863881748169 33.7848439284835, -84.2963746470588 33.7897689411765, -84.2979002513655 33.790508814658, -84.2978883265306 33.7851126734694, -84.300035153059 33.78268675, -84.3043408314983 33.78004925))' wkt_string
UNION ALL
SELECT 'POINT(-84.2998716702097 33.7796025711153)' wkt_string
)
SELECT ST_GEOGFROMTEXT(wkt_string) geo
FROM objects
this is the function i was looking for:
ST_CLOSESTPOINT(geography_1, geography_2[, use_spheroid]).
Use ST_Distance function to compute shortest distance between shapes:
WITH objects AS(
SELECT
'POLYGON((-84.3043408314983 33.78004925, -84.3058929975152 33.7780287948446, -84.3026549053438 33.77962155, -84.3018234603607 33.7798783, -84.3041030408163 33.7785105714286, -84.2983655895464 33.7814847396304, -84.2869801170094 33.7772419185107, -84.2842584693878 33.7827876938775, -84.2863881748169 33.7848439284835, -84.2963746470588 33.7897689411765, -84.2979002513655 33.790508814658, -84.2978883265306 33.7851126734694, -84.300035153059 33.78268675, -84.3043408314983 33.78004925))'
AS poly,
'POINT(-84.2998716702097 33.7796025711153)' AS point
)
SELECT ST_Distance(ST_GEOGFROMTEXT(poly), ST_GEOGFROMTEXT(point))
FROM objects
One caveat - it computes distance between point and polygon, so if the point is inside the polygon, the distance is 0. If you really want distance to polygon boundary, add ST_Boundary to the mix:
WITH objects AS(
...
)
SELECT ST_Distance(ST_Boundary(ST_GEOGFROMTEXT(poly)), ST_GEOGFROMTEXT(point))
FROM objects
Using BigQuery Geo Viz,
I am trying to visualize a polygon and its centroid point, simultaneously on the same map.
I tried the ST_UNION function but could not really combine the two GEOGRAPHYs.
Any idea how to visualize both GEOGRAPHYs.
Polygon:
POLYGON((-95.7082555 29.9212101, -95.665885 29.907145, -95.7742806214083 29.82947355, -95.7303605 29.8538605, -95.659484 29.901497, -95.662932 29.894958, -95.8441482 29.7265376, -95.646749 29.905534, -95.810012 29.719363, -95.664174 29.883618, -95.639718 29.910045, -95.652796 29.89204, -95.649915 29.886317, -95.650089 29.881912, -95.641443 29.897741, -95.632912 29.911674, -95.653458 29.864561, -95.635056 29.864431, -95.636533 29.757219, -95.623339 29.903466, -95.597235 29.75367, -95.3636989932886 29.8063167449664, -95.575123 29.920295, -95.3944858832763 29.94248964622, -95.147033 30.013214, -95.586588 29.947706, -95.456723 31.3287239, -95.69717 29.96911, -95.674433 29.943844, -95.678203 29.935184, -95.7082555 29.9212101))
Centroid point:
POINT(-95.5606651932764 30.2307053050834)
Try selecting the two structures separately and using UNION ALL to gather them in the same visualization:
SELECT ST_GeogFromText('POLYGON((-95.7082555 29.9212101, -95.665885 29.907145, -95.7742806214083 29.82947355, -95.7303605 29.8538605, -95.659484 29.901497, -95.662932 29.894958, -95.8441482 29.7265376, -95.646749 29.905534, -95.810012 29.719363, -95.664174 29.883618, -95.639718 29.910045, -95.652796 29.89204, -95.649915 29.886317, -95.650089 29.881912, -95.641443 29.897741, -95.632912 29.911674, -95.653458 29.864561, -95.635056 29.864431, -95.636533 29.757219, -95.623339 29.903466, -95.597235 29.75367, -95.3636989932886 29.8063167449664, -95.575123 29.920295, -95.3944858832763 29.94248964622, -95.147033 30.013214, -95.586588 29.947706, -95.456723 31.3287239, -95.69717 29.96911, -95.674433 29.943844, -95.678203 29.935184, -95.7082555 29.9212101))') t UNION ALL SELECT ST_GeogFromText('POINT(-95.5606651932764 30.2307053050834)') t
If your intention is to show the geometry and the point in the same visualization it will work as you can see in the image below:
Please let me know if this is what you are looking for
In case of the simple scenario you presented in the question of having just one polygon and its centroid below simple solution works
#standardSQL
WITH objects AS (
SELECT 'POLYGON((-95.7082555 29.9212101, -95.665885 29.907145, -95.7742806214083 29.82947355, -95.7303605 29.8538605, -95.659484 29.901497, -95.662932 29.894958, -95.8441482 29.7265376, -95.646749 29.905534, -95.810012 29.719363, -95.664174 29.883618, -95.639718 29.910045, -95.652796 29.89204, -95.649915 29.886317, -95.650089 29.881912, -95.641443 29.897741, -95.632912 29.911674, -95.653458 29.864561, -95.635056 29.864431, -95.636533 29.757219, -95.623339 29.903466, -95.597235 29.75367, -95.3636989932886 29.8063167449664, -95.575123 29.920295, -95.3944858832763 29.94248964622, -95.147033 30.013214, -95.586588 29.947706, -95.456723 31.3287239, -95.69717 29.96911, -95.674433 29.943844, -95.678203 29.935184, -95.7082555 29.9212101))' wkt_string UNION ALL
SELECT 'POINT(-95.5606651932764 30.2307053050834)'
)
SELECT ST_GEOGFROMTEXT(wkt_string) geo
FROM objects
and this can be visualized with different tools - like in below example
For more realistic scenario, when you have many polygons and need to visulaize them along with their centroids - you can use below approach (based on example with us states)
#standardSQL
SELECT state_geom state, ST_CENTROID(state_geom) centroid
FROM `bigquery-public-data.utility_us.us_states_area`
with result as below
which can be visualized as in below examples (just showing few states to get an idea)
And finally, you can combine all such polygons (states in this example) with their centroids in nice visualization as below
Another (of many endless options) thing you can do is to add some metrics and more attributes to the query - for example state_name and area_land_meters and make your visualization data driven and with dynamic tooltips like in below example
Say I have following data in table addresses:
physicalState physicalPostalCode geometry
------------------------------------------------------------------------------
PA 15340 0xE6100000010CAC1C5A643B1354C02D431CEBE2264440
OK 74576 0xE6100000010C7DD0B359F50158C079E9263108544140
WV 26033 0xE6100000010CE8D9ACFA5C2554C0273108AC1CEA4340
WV 26033 0xE6100000010C36AB3E575B2554C0C3D32B6519EA4340
I want to
select *
from addresses
where geometry = GEOMETRY::STPointFromText('POINT (40.3038 -80.3005)', 4326)
Finding it very difficult to figure this out...
Try use method [STContains]
like this condition:
geometry.STContains(GEOMETRY::STPointFromText('POINT (40.3038 -80.3005)', 4326))
OKIE! Figured this one out... One thing worth noting, x/y coordinates were flip flopped. That helped to frustrate things. stupid me.
Either way, this is what in order able to query the database by specific points:
select * from addresses
WHERE geometry.ToString() = 'POINT (-80.3005 40.3038)'
Also, to credit #Adam Silenko, his solution also works as such:
select *
from addresses
where geometry.STContains(GEOMETRY::STPointFromText('POINT (-80.3005 40.3038)', 4326)) = 1
Thanks!
I wrote a simple web application that lets you mark flea market stands on a google map.
Each stand is stored in a sqlite3 database with its geolocation and other information.
This is the CREATE statement for the stands table:
CREATE TABLE stands (
id INTEGER PRIMARY_KEY,
name TEXT,
address TEXT,
u REAL,
v REAL,
);
u and v are respectively Latitude and Longitude.
Additionally I have a cities table that stores the name and geographic bounds of each city which host a stand. This is used to let users quickly navigate between cities.
CREATE TABLE cities
(name TEXT PRIMARY_KEY,
u_min REAL,
u_max REAL,
v_min REAL,
v_max REAL);
When a new stand is added, a new row is added to the cities table or if the stand is in a known city, only the bounds of the city are updated if needed.
Here are some sample stands:
592077673|Kierrätystori Rovaniemellä|Urheilukatu 1, 96100 Rovaniemi, Suomi|66.4978306921681|25.7220569153442
1321495145|Kruununhaka|Liisankatu, 00170 Helsinki, Suomi|60.1742596|24.9555782
571688977|Viikki asukastalo LAVAn edusta|Biologinkatu 5, 00790 Helsinki, Suomi|60.2342312|25.04058
563089951|Hämeentie 156|Hämeentie 156, 00560 Helsinki, Suomi|60.2130467082539|24.9785856067459
518892420|Joensuu - Ilosaari|Siltakatu 1, 80100 Joensuu, Finland|62.5990455742272|29.7706540507875
and cities:
Rovaniemi|66.4978306921681|66.4978306921681|25.7220569153442|25.7220569153442
Helsinki|60.1577049447137|60.2556221042622|24.9216988767212|25.0662129772156
Järvenpää|60.4513724|60.4513724|25.0819323000001|25.0819323000001
Joensuu|62.5990455742272|62.5990653244875|29.7706540507874|29.7706540507875
Vantaa|60.2731724937748|60.2731724937748|24.9571491285278|24.9571491285278
The issue I'm having is retrieving the the number of stands per cities.
So far I've been using the following query:
SELECT cities.name AS city,
cities.u_min,
cities.u_max,
cities.v_min,
cities.v_max,
count(stands.id) AS count
FROM cities
LEFT OUTER JOIN stands
ON ((stands.u BETWEEN cities.u_min AND cities.u_max)
AND(stands.v BETWEEN cities.v_min AND cities.v_max))
GROUP BY cities.name;
This returns:
Helsinki|60.1577049447137|60.2556221042622|24.9216988767212|25.0662129772156|9
**Joensuu|62.5990455742272|62.5990653244875|29.7706540507874|29.7706540507875|0**
Järvenpää|60.4513724|60.4513724|25.0819323000001|25.0819323000001|1
Rovaniemi|66.4978306921681|66.4978306921681|25.7220569153442|25.7220569153442|1
Vantaa|60.2731724937748|60.2731724937748|24.9571491285278|24.9571491285278|1
Which is not correct as the city named Joensuu does have 1 stand in its boundaries:
518892420|Joensuu - Ilosaari|Siltakatu 1, 80100 Joensuu, Finland|62.5990455742272|29.7706540507875
But the following query returns the expected stand:
SELECT * FROM stands where u between 62.5990455742272 and 62.5990653244875 and v between 29.7706540507874 and 29.7706540507875;
I really can't understand what is going wrong here.
Any help would be greatly appreciated.
By the way, I imported this database to Mysql and the same thing happens so I doubt this is a sqlite3 bug.
I think this has to do with floating point precision error. One of the ways to deal with such problems is to introduce a small number and add it to your boundaries to make them a little wider - that eliminates precision errors.
One approach is to widen boundaries in every query directly:
SET #e = 0.0000000000001;
SELECT cities.name AS city,
cities.u_min,
cities.u_max,
cities.v_min,
cities.v_max,
count(stands.id) AS count
FROM cities
LEFT OUTER JOIN stands
ON ((stands.u BETWEEN cities.u_min - #e AND cities.u_max + #e)
AND(stands.v BETWEEN cities.v_min - #e AND cities.v_max + #e))
GROUP BY cities.name;
Another approach is to store the widened boundaries in the cities table:
SET #e = 0.0000000000001;
UPDATE cities
SET cities.u_min = cities.u_min - #e,
cities.u_max = cities.u_max + #e,
cities.v_min = cities.v_min - #e,
cities.v_max = cities.v_max + #e;
P.S. I am not sure if the variable syntax works in SQLite, but if doesn't, just substitute all #e with 0.0000000000001.
The reason is that you use LEFT JOIN, so it includes all cities, regardless of whether there is a match in the stands table. Notice how COUNT returns 0 for that row.
Just use INNER JOIN instead of LEFT JOIN. That will tell MySQL to only return rows for which the condition in ON is met.
UPD: I misunderstood the question, so this answer is wrong. I'll post another answer.
I've four tables:
characters
guid
name
gender
class
race
online
character_arena_stats
guid
personal_rating
matchmaker_rating
arena_team_member
arenateamid
played_season
played_week
wons_season
wons_week
arena_team
arenateamid
captain_guid
and I need to get character details(race,class,name,gender,online) and team information(personal_rating,matchmaker_rating,played_season,played_week,wons_season,wons_week,captain_guid), but can't get it working. My query is:
$result=mysql_query("SELECT
c.guid,
c.name,
c.gender,
c.class,
c.online,
c.race,
atm.guid,
atm.played_season,
atm.played_week,
atm.wons_season,
atm.wons_week,
atm.arenateamid,
cas.personal_rating,
cas.guid,
cas.matchmaker_rating,
at.arenateamid,
at.captainguid
FROM
character_arena_stats cas,
arena_team_member atm,
characters c,
arena_team at
WHERE c.guid = cas.guid AND atm.arenateamid = ".$entry." AND at.arenateamid = ".$entry."");
It should return only members whose guid is equal to c.guid, cas.guid, atm,guid and those, whose atm.arenateamid is equal to at.arenateamid. Insted, it returns a lot of random members.
Thanks and sorry for my english.
Since you're not specifying how records in the arena tables should join to records in the character tables, you're getting a cross join, which returns every combination of character records with arena records.
When you say "I want to get them all," what exactly do you mean? Find a starting point for your query. For example: are you looking for all characters, organized by team, with their details and arena stats? Or, for each character, all the teams on which they participate?
Defining the requirements a little more clearly will help us suggest solutions. :)
Update: Actually, having read the query a little more closely, I believe I can infer what you're looking for:
SELECT
c.guid,
c.name,
c.gender,
c.class,
c.online,
c.race,
atm.guid
atm.played_season,
atm.played_week,
atm.wons_season,
atm.wons_week,
atm.arenateamid,
cas.personal_rating,
cas.guid,
cas.matchmaker_rating,
at.arenateamid,
at.captainguid
FROM
character_arena_stats cas,
arena_team_member atm,
characters c,
arena_team at
WHERE c.guid = cas.guid
and c.guid = atm.guid
and atm.arenateamid = at.arenateamid
AND at.arenateamid = ".$entry."
Note that the Arena Team and Character tables are now joined based on the team captain's GUID - this will avoid the cross join ("random rows") problem. Also, Arena Team Members is now joined to Arena Teams, and the filter parameter is only checked against the Teams table.
Not sure this will give you precisely what you want without knowing more about your data and requirements - I believe what it will give you is a list of each team captain, their arena stats, along with their team and team members' stats. Hopefully this will move you forward. Good luck!
uhh mate not sure what you got there,... to lazy myself to write the query for you, have a look again at dev.mysql.com refs should be straight forwared.
also your character_arena_stats table, shouldn't there be a ref to a arena table or something?
guid
arena_id ?
personal_rating
matchmaker_rating
see more here for normalization
Yeah, I am not really sure exactly what you're trying to do, but based on the description ...
Your Model seems to be all wrong and will never produce the results you are looking for. For instance, there are no Keys tying arena_team and arena_team_member to characters and character_arena_stats.
Secondly, this condition:
"WHERE c.guid = cas.guid AND atm.arenateamid = ".$entry." AND at.arenateamid = ".$entry);
is incorrect for this statement: "It should return only members ... whose atm.arenateamid is equal to at.arenateamid".
Rather, it could be rewritten as follows:
"WHERE c.guid = cas.guid AND atm.arenateamid = at.arenateamid AND atm.arenateamid = ".$entry);
Regardless though, because of the aforementioned reasons, the query will never returned expected results, at least based on what I understood from your post.
SIDE NOTE: This is PHP code, so I do not know why you are tagging it as jQuery.
Good Luck,