In SQL Server 2008 R2, we have a table with a field of data type geography. When queried with
SELECT rowid,GeoCoor,
GeoCoor.STSrid as SRID,
GeoCoor.Lat as Lat,
GeoCoor.Long as Long
FROM dbo.Locations
we get rows like this:
╔═══════╦════════════════════════════════════════════════╦══════╦══════════════════╦═══════════════════╗
║ rowid ║ GeoCoor ║ SRID ║ Lat ║ Long ║
╠═══════╬════════════════════════════════════════════════╬══════╬══════════════════╬═══════════════════╣
║ 1092 ║ 0xE6100000010C82C540E751804240BA86EFD400B45BC0 ║ 4326 ║ 37.0024994913356 ║ -110.812550767815 ║
╚═══════╩════════════════════════════════════════════════╩══════╩══════════════════╩═══════════════════╝
All of our data are points, not lines or polygons, and we are using SRID 4326.
I am trying to UPDATE the GeoCoor field of a record with the binary value of another geographic point stored in the table. Here is my code:
DECLARE #coor1 geography
SET #coor1 = geography::STGeomFromWKB(0xE6100000010C82C540E751804240BA86EFD400B45BC0,4326)
UPDATE dbo.Locations
SET GeoCoor = #coor1
WHERE RowID = 2657
However, the SET #coor1 = statement triggers an error in SQL Server Management Studio:
A .NET Framework error occurred during execution of user-defined routine or aggregate "geography":
System.FormatException: 24201: Latitude values must be between -90 and 90 degrees.
System.FormatException:
at Microsoft.SqlServer.Types.GeographyValidator.ValidatePoint(Double x, Double y, Nullable`1 z, Nullable`1 m)
at Microsoft.SqlServer.Types.Validator.BeginFigure(Double x, Double y, Nullable`1 z, Nullable`1 m)
at Microsoft.SqlServer.Types.ForwardingGeoDataSink.BeginFigure(Double x, Double y, Nullable`1 z, Nullable`1 m)
at Microsoft.SqlServer.Types.CoordinateReversingGeoDataSink.BeginFigure(Double x, Double y, Nullable`1 z, Nullable`1 m)
at Microsoft.SqlServer.Types.OpenGisWkbReader.ReadFirstPoint(ByteOrder byteOrder)
at Microsoft.SqlServer.Types.OpenGisWkbReader.ParseWkbPointWithoutHeader(ByteOrder byteOrder)
at Microsoft.SqlServer.Types.OpenGisWkbReader.Read(OpenGisType type, Int32 srid)
at Microsoft.SqlServer.Types.SqlGeography.GeographyFromBinary(OpenGisType type, SqlBytes binary, Int32 srid)
Based on the initial query results, you can plainly see that the Latitude of 37.002499... is indeed between -90 and 90. It is the Longitude that is not between -90 and 90.
I believe this is a .NET bug in the geography::STGeomFromWKB method, that is incorrectly transposing the Lat and Long from the WKB data (or perhaps the .Lat and .Long methods are in error?!). My questions are:
Can anyone tell me if I'm overlooking something, or should I go ahead and submit this to Microsoft Connect?
Can someone reproduce this bug in a later version of SQL Server (2016)? or has it been fixed?
After perusing other sites I thought to reverse the order of my Lat/Long. That seemed to work.
SELECT Geography::Point(Latitude,Longitude, 4326) as c
FROM na.MyTable
where Latitude Is Not Null
That generates the spatial data I am looking for (but of course something else is broken) :)
Related
I try to perform arithmetic functions on a table in mysql database. on the table there are 5 field where the first field is the primary key and other fields is an integer data type.
Assume a field that has a data type is integer W, X, Y, and, Z. I want to do the calculation by the following formula:
(Xi - Xavg)^2
Xi = value of record i
Xavg = average value of field X
I write my query like this:
SELECT W, X, Y, Z, POW(W - AVG(W),2), POW(X - AVG(X),2), POW(Y - AVG(Y),2), POW(Z - AVG(Z),2)
FROM nilai
And here the result:
But the result only showing the first record. is there any way, so i can display all the records and the results of the calculations?
So I noticed that after n=20 the factorial function given in LearnYouAHaskell (below) craps out because of the finite work range of the Int type.
factorial :: Int -> Int
factorial 0 = 1
factorial n * factorial (n-1)
Using factorial :: Integer -> Integer fixes the issue nicely, but it brought to mind the question. Supposedly Integer is slightly slower than Int so ideally (and I know I'm pinching pennies here) I'd want my factorial function to only resort to Integer when the input is greater than 20 and retain the Int->Int type for the smaller numbers. Seems like there should be an elegant solution for this using if-then-else or guards, but keep running into syntactic pepper (error messages)
You can make a hackish solution without dependent types by using either a sum type and growing when needed or delaying the cast to Integer till the end in some cases. I don't expect either solution would perform better than using Integer - do not fear the Integer, gmp and mpir are quite good.
The casting solution is something like:
selectiveFactorial :: Integer -> Integer
selectiveFactorial i
| i < 20 = fromIntegral $ factorial (fromIntegral i :: Int)
| otherwise = factorial i
factorial :: Integral a => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)
As Rein Henrichs said you could do these things in a language with dependent types, which Haskell does not (yet, quite) have. In Idris, say, it would look something like
factorial : (n : Int) -> if n <= 20 then Int else Integer
factorial n with (n <= 20)
factorial n | True = thisfactorial n
factorial n | False = thatfactorial n
But how will you use this result? Well, you'll need to do the comparison to figure out what type to expect, and when all is said and done, I don't see how you've won anything. For completeness, the use site could look something like this:
use : Int -> Integer
use n with (factorial n)
use n | fn with (n <= 20)
use n | fn | False = fn
use n | fn | True = cast fn
Note that the order of the with clauses is significant! The fn binding gets type if n <= 20 then Int else Integer; for reasons I don't entirely understand, the n <= 20 test must be to the right of that in order for the pattern match to affect its type.
It can't be done. There are things you can do however:
Make the type more generic: factorial :: Num a => a -> a;
This allows the user of your function to decide what runtime penalties he wants to occur vs. what range of numbers is permissible.
Use a sum type like data PossiblyBig = Small Int | Big Integer, and then have an implementation instance Num PossiblyBig that encodes things that fit into Int as Small, and things that don't fit as Big; AFAIK Integer already works like that (look up the GMP implementation if you want to know for sure), so this is more of a general example than advice as to what you should do in this particular situation.
Making the type of a function depend on its values is exactly what dependent types are for. Unfortunately, Haskell does not have dependent types so this cannot be done.
I have a field in the mysql database that contains data like the following:
Q16
Q32
L16
Q4
L32
L64
Q64
Q8
L1
L4
Q1
And so forth. What I'm trying to do is pull out, let's say, all the values that start with Q which is easy:
field_name LIKE 'Q%'
But then I want to filter let's say all the values that have a number higher than 32. As a result I'm supposed to get only 'Q64', however, I also get Q4, Q8 and so for as I'm comparing them as strings so only 3 and the respective digit are compared and the numbers are in general taken as single digits, not as integers.
As this makes perfect sense, I'm struggling to find a solution on how to perform this operation without pulling all the data out of the database, stripping out the Qs and parsing it all to integers.
I did play around with the CAST operator, however, it only works if the value is stored as string AND it contains only digits. The parsing fails if there's another character in there..
Extract the number from the string and cast it to a number with *1 or cast
select * from your_table
where substring(field_name, 1, 1) = 'Q'
and substring(field_name, 2) * 1 > 32
Database stores 4 points with coordinates like:
Name | Lat | Long
Point 1 | 11.111 | 22.222
Point 2 | 22.222 | 33.333
Point 3 | 44.444 | 55.555
Point 4 | 66.666 | 77.777
Technology:
MS SQL Server
Web application gets current user lat and long via HTML5, then it should calculate what points of those 4 are nearer then 0.5 km. How?
It should display Point 1 and Point 2 based on this illustration:
Using Sql Server:
You can find distance between two coordinates in KiloMetres using the below function
CREATE FUNCTION dbo.fnCalcDistanceKM(#lat1 FLOAT, #lat2 FLOAT, #lon1 FLOAT, #lon2 FLOAT)
RETURNS FLOAT
AS
BEGIN
RETURN ACOS(SIN(PI()*#lat1/180.0)*SIN(PI()*#lat2/180.0)+COS(PI()*#lat1/180.0)*COS(PI()*#lat2/180.0)*COS(PI()*#lon2/180.0-PI()*#lon1/180.0))*6371
END
Sample Usage:
select [dbo].[fnCalcDistanceKM](13.077085,80.262675,13.065701,80.258916)
Reference
Using Entity Framework(dot net):
Entity framework 5.0 allows you to write LINQ expression like this
private Facility GetNearestFacilityToJobsite(DbGeography jobsite)
{
var q1 = from f in context.Facilities
let distance = f.Geocode.Distance(jobsite)
where distance < 500 * 1609.344
orderby distance
select f;
return q1.FirstOrDefault();
}
Reference
I hope this is enough to get you started.
You need to convert your point to the geography data type. Then you can do a WHERE #here.STDistance(testPoint) < 500.
The basics of using the geogrpahy point to calculate distance can be found in this question.
I want to do the following to my database:
UPDATE Addresses
SET Latitude = 1000, Longitude = 1000
WHERE Latitude IS NULL AND Longitude IS NULL
1000 is not a valid latitude or longitude. Latitude and Longitude are new columns in my database, and I don't want any of the fields to be null. I handle invalid latitude and longitude values in my application, but having them null creates difficulties.
When I try to run this query, I get the following error:
Msg 8115, Level 16, State 8, Line 3
Arithmetic overflow error converting int to data type numeric.
The statement has been terminated.
The datatypes of the Latitude and Longitude column are both Decimal(18,15). I assume that I have to write these decimal entries in a particular way, but I can't work out what it is.
Could someone enlighten me?
You are overflowing your specified parameters for the datatype.
DECIMAL(18,15) means you have 18 total places, and 15 of those are right of the decimal. This leaves 3 places left of the decimal, and 1000 is a four digit number.
You need to either change the datatype to something like DECIMAL(18,14) or use a value like 999.999999999999999.