Query Overpass API for roads in a specific country - openstreetmap

I'm trying to construct a query of all 'highway=' ways in a specific area in overpass. I've been defaulting to using the {{bbox}} - but I really would prefer to do it by country.
I've tried using 'nominatimArea:' instead of {{bbox}} but I get a parse error ' line 8: parse error: ')' expected - '(' found. ' on the below:
/*
This shows the roads in nepal.
*/
[out:json];
(
way ["highway"~"motorway|trunk|primary|motorway_link|trunk_link|primary_link|unclassified|tertiary|secondary|track|path"]({{nominatimArea:Nepal}});
);
out meta;
>;
out skel qt;
ALSO ... if I try this...I only (weirdly) get one area - no ways (maybe the relations are a mess?)
/*
This shows the roads in nepal.
*/
[out:json];
(area[name="Nepal"];
way(area) ["highway"~"motorway|trunk|primary|motorway_link|trunk_link|primary_link|unclassified|tertiary|secondary|track|path|residential|service"];
);
out meta;
>;
out skel qt;
Returns this one item (and it is an area NOT a way)
Note: I know this is a large query - but I really just need the url to the raw JSON (like this) - not the actual overpass map result.

Got it.
/*
This shows the roads in nepal.
*/
[out:json];
area[name="नेपाल"];
(way["highway"~"motorway|trunk|primary|motorway_link|trunk_link|primary_link|unclassified|tertiary|secondary|track|path|residential|service|secondary_link|tertiary_link"](area);
);
out meta;
>;
out skel qt;

Related

Question mark in laravel toSQL()

I get this output when trying to use toSQL() to debug my queries.
Laravel code:
$services = Service::latest()->where('status', '=', '0');
Output SQL:
"select * from `services` where `status` = ? order by `created_at` desc"
How can I get a proper query without ? mark? Thanks!
To view the data that will be substituted into the query string you can call the getBindings() function on the query like
below.
$query = User::first()->jobs();
dd($query->toSql(), $query->getBindings());
The array of bindings get substituted in the same order the ? appear in the SQL statement.
check this link

DB2 SQL Error: SQLCODE=-302 while executing prepared statement

I have a SQL query which takes user inputs hence security flaw is present.
The existing query is:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID, 'I' ||
LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
, ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, Other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (" +TriggerType+ ");
I changed it to accept TriggerType from setString like:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID,
'I' || LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (?);
Setting trigger type as below:
if (StringUtils.isNotBlank(request.getTriggerType())) {
preparedStatement.setString(1, triggerType != null ? triggerType.toString() : "");
}
Getting error as
Caused by: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.19.26
The -302 SQLCODE indicates a conversion error of some sort.
SQLSTATE 22001 narrows that down a bit by telling us that you are trying to force a big string into a small variable. Given the limited information in your question, I am guessing it is the XMLCAST that is the culprit.
DB2 won't jam 30 pounds of crap into a 4 pound bag so to speak, it gives you an error. Maybe giving XML some extra room in the cast might be a help. If you need to make sure it ends up being only 4 characters long, you could explicitly do a LEFT(XMLCAST( ... AS VARCHAR(64)), 4). That way the XMLCAST has the space it needs, but you cut it back to fit your variable on the fetch.
The other thing could be that the variable being passed to the parameter marker is too long. DB2 will guess the type and length based on the length of ALERT_TYPE. Note that you can only pass a single value through a parameter marker. If you pass a comma separated list, it will not behave as expected (unless you expect ALERT_TYPE to also contain a comma separated list). If you are getting the comma separated list from a table, you can use a sub-select instead.
Wrong IN predicate use with a parameter.
Do not expect that IN ('AAAA, M250, ABCD') (as you try to do passing a comma-separated string as a single parameter) works as IN ('AAAA', 'M250', 'ABCD') (as you need). These predicates are not equivalent.
You need some "string tokenizer", if you want to pass such a comma-separated string like below.
select t.*
from
(
select XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE
from table(values xmlparse(document '<alertTypeConfig><biqCode>M250, really big code</biqCode></alertTypeConfig>')) IAC(INTL_ALERT_TYPE_CONFIG)
) t
--WHERE ALERT_TYPE IN ('AAAA, M250, ABCD')
join xmltable('for $id in tokenize($s, ",\s?") return <i>{string($id)}</i>'
passing cast('AAA, M250 , ABCD' as varchar(200)) as "s"
columns token varchar(200) path '.') x on x.token=t.ALERT_TYPE
;
Run the statement as is. Then you may uncomment the string with WHERE clause and comment out the rest to see what you try to do.
P.S.:
The error you get is probably because you don't specify the data type of the parameter (you don't use something like IN (cast(? as varchar(xxx))), and db2 compiler assumes that its length is equal to the length of the ALERT_TYPE expression (4 bytes).

How to get points from OpenStreetMap of a certain country?

i'm trying to get the list of all schools in my country, and after several tries i write the following query that works with no errors on http://overpass-turbo.eu:
/*
This has been generated by the overpass-turbo wizard.
The original search was:
“amenity=school”=“yes”
*/
[out:json][timeout:60];
// gather results
(
// query part for: “amenity=school”
node[amenity=school]({{geocodeBbox:Italia}});
way[amenity=school]({{geocodeBbox:Italia}});
relation[amenity=school]({{geocodeBbox:Italia}});
);
// print results
out body;
>;
out skel qt;
I used geocodeBbox to select all schools of Italy because geocodeId and geocodeArea (please refer to documentation) give me the following errors:
Error: line 10: parse error: ')' expected - '(' found.
Error: line 11: parse error: ')' expected - '(' found.
Error: line 11: parse error: ';' expected - ')' found.
Error: line 12: parse error: ')' expected - '(' found.
Error: line 12: parse error: ';' expected - ')' found.
Error: line 13: parse error: Unknown type ")"
Error: line 13: parse error: An empty query is not allowed
Error: line 13: parse error: Unknown type ";"
Error: line 15: parse error: An empty query is not allowed
Anyway the problem is that the query selects even schools that are not in Italy (for example there is a school from Croatia).
So, how to get exactly the points from a certain country?
Anyway the problem is that the query selects even schools that are not in Italy (for example there is a school from Croatia).
That's correct. A bounding box (bbox) is a rectangle, not a polygon. Therefore it will always include a little bit more, except if you have a rectangle-shaped country that is also perfectly aligned with the given bbox ;)
Try this query instead:
[out:json][timeout:600];
// gather results
{{geocodeArea:Italia}}->.searchArea;
(
// query part for: “amenity=school”
node[amenity=school](area.searchArea);
way[amenity=school](area.searchArea);
relation[amenity=school](area.searchArea);
);
// print results
out body;
>;
out skel qt;

UndefinedFunction: ERROR: function st_distance(geography, geometry, numeric) does not exist

I wanna to order by distance, but I got the error
UndefinedFunction: ERROR: function st_distance(geography, geometry, numeric) does not exist
by .order("ST_Distance(lonlat, ST_Geomfromtext('#{point}'), #{radius}) ")
If I removed the above line , it works fine.
What's wrong with it ?
model
scope :nearby, lambda { |radius_in_km, lon, lat|
point = GEOG_FACTORY.point(lon, lat)
radius = radius_in_km.to_f*1000
where("ST_DWithin(lonlat, ST_GeomFromText('#{point}'), #{radius} ) ")
.order("ST_Distance(lonlat, ST_Geomfromtext('#{point}'), #{radius}) ")
}
more detail error log
PG::UndefinedFunction: ERROR: function st_distance(geography, geometry, numeric) does not exist
LINE 1: ...4028 6.530438999999999)'), 100000.0 ) ) ORDER BY ST_Distanc...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
: SELECT "weather_logs".* FROM "weather_logs" WHERE (ST_DWithin(lonlat, ST_GeomFromText('POINT (101.3034028 6.530438999999999)'), 100000.0 ) ) ORDER BY ST_Distance(lonlat, ST_Geomfromtext('POINT (101.3034028 6.530438999999999)'), 100000.0) , "weather_logs"."datetime" ASC LIMIT 20000
Completed 200 OK in 161ms (Views: 0.2ms | ActiveRecord: 5.4ms)
You are mixing geography and geometry types, that is what the error message means. If you look at the ST_DWithin docs, you will see that the signature are ST_DWithin (geometry, geometry, distance) or ST_DWithin (geography, geography, distance).
I don't know much about Ruby, so am not sure if there is a GEOM_Factory equivalent of the GEO_Factory you have used, but if you use ST_GeogFromText instead of ST_GeomFromText in your where and order by clauses, then you will be dealing with two geographies, which should solve your issue.
As your coordinates are in lat/lon, 4326, it is appropriate to use the geography datatype. If you want to know more about the practicalities of geometry vs geography, see this gis.stackexchange question.

Can I get the table names from an SQL query with Perl's DBI?

I am writing small snippets in Perl and DBI (SQLite yay!)
I would like to log some specific queries to text files having the same filename as that of the table name(s) on which the query is run.
Here is the code I use to dump results to a text file :
sub dumpResultsToFile {
my ( $query ) = #_;
# Prepare and execute the query
my $sth = $dbh->prepare( $query );
$sth->execute();
# Open the output file
open FILE, ">results.txt" or die "Can't open results output file: $!";
# Dump the formatted results to the file
$sth->dump_results( 80, "\n", ", ", \*FILE );
# Close the output file
close FILE or die "Error closing result file: $!\n";
}
Here is how I can call this :
dumpResultsToFile ( <<" END_SQL" );
SELECT TADA.fileName, TADA.labelName
FROM TADA
END_SQL
What I effectively want is, instead of stuff going to "results.txt" ( that is hardcoded above ), it should now go to "TADA.txt".
Had this been a join between tables "HAI" and "LOL", then the resultset should be written to "HAI.LOL.txt"
Is what I am saying even possible using some magic in DBI?
I would rather do without parsing the SQL query for tables, but if there is a widely used and debugged function to grab source table names in a SQL query, that would work for me too.
What I want is just to have a filename
that gives some hint as to what query
output it holds. Seggregating based on
table name seems a nice way for now.
Probably not. Your SQL generation code takes the wrong approach. You are hiding too much information from your program. At some point, your program knows which table to select from. Instead of throwing that information away and embedding it inside an opaque SQL command, you should keep it around. Then your logger function doesn't have to guess where the log data should go; it knows.
Maybe this is clearer with some code. Your code looks like:
sub make_query {
my ($table, $columns, $conditions) = #_;
return "SELECT $columns FROM $table WHERE $conditions";
}
sub run_query {
my ($query) = #_;
$dbh->prepare($query);
...
}
run_query( make_query( 'foo', '*', '1=1' ) );
This doesn't let you do what you want to do. So you should structure
your program to do something like:
sub make_query {
my ($table, $columns, $conditions) = #_;
return +{
query => "SELECT $columns FROM $table WHERE $conditions",
table => $table,
} # an object might not be a bad idea
}
sub run_query {
my ($query) = #_;
$dbh->prepare($query->{query});
log_to_file( $query->{table}.'.log', ... );
...
}
run_query( make_query( 'foo', '*', '1=1' ) );
The API is the same, but now you have the information you need to log
the way you want.
Also, consider SQL::Abstract for dynamic SQL generation. My code
above is just an example.
Edit: OK, so you say you're using SQLite. It has an EXPLAIN command
which you could parse the output of:
sqlite> explain select * from test;
0|Trace|0|0|0|explain select * from test;|00|
1|Goto|0|11|0||00|
2|SetNumColumns|0|2|0||00|
3|OpenRead|0|2|0||00|
4|Rewind|0|9|0||00|
5|Column|0|0|1||00|
6|Column|0|1|2||00|
7|ResultRow|1|2|0||00|
8|Next|0|5|0||00|
9|Close|0|0|0||00|
10|Halt|0|0|0||00|
11|Transaction|0|0|0||00|
12|VerifyCookie|0|1|0||00|
13|TableLock|0|2|0|test|00|
14|Goto|0|2|0||00|
Looks like TableLock is what you would want to look for. YMMV, this
is a bad idea.
In general, in SQL, you cannot reliably deduce table names from result set, both for theoretical reasons (the result set may only consist of computed columns) and practical (the result set never includes table names - only column names - in its data).
So the only way to figure out the tables used is to stored them with (or deduce them from) the original query.
I've heard good things about the parsing ability of SQL::Statement but never used it before now myself.
use SQL::Statement;
use strict;
use warnings;
my $sql = <<" END_SQL";
SELECT TADA.fileName, TADA.labelName
FROM TADA
END_SQL
my $parser = SQL::Parser->new();
$parser->{RaiseError} = 1;
$parser->{PrintError} = 0;
my $stmt = eval { SQL::Statement->new($sql, $parser) }
or die "parse error: $#";
print join',',map{$_->name}$stmt->tables;