Related
I have a table in MS SQL Server 2016. the table has a column called notes varchar(255)
The data that contains in the notes column contains notes entry by end user.
Select ServiceDate, notes from my_table
ServiceDate, notes
--------------------------------------
9/1/2022 The order was called in AB13456736
9/1/2022 AB45876453 not setup
9/2/2022 Signature for AB764538334
9/2/2022 Contact for A0943847432
9/3/2022 Hold off on AB73645298
9/5/2022 ** Confirmed AB88988476
9/6/2022 /AB9847654 completed
I would like to be able to extract the word AB% from the notes column. I know the ABxxxxxxx is always 10 characters. Because the ABxxxxxx always entered in different position, it's difficult to use exact extract where to look for. I have tried substring(), left() functions and because the value AB% is always in different positions, I can't get it to extract. is there a method I can use to do this?
thanks in advance.
Assuming there is only ONE AB{string} in notes, otherwise you would need a Table-Valued Function.
Note the nullif(). This is essentially a Fail-Safe if the string does not exist.
Example
Declare #YourTable Table ([ServiceDate] varchar(50),[notes] varchar(50)) Insert Into #YourTable Values
('9/1/2022','The order was called in AB13456736')
,('9/1/2022','AB45876453 not setup')
,('9/2/2022','Signature for AB764538334')
,('9/2/2022','Contact for A0943847432')
,('9/3/2022','Hold off on AB73645298')
,('9/5/2022','** Confirmed AB88988476')
,('9/6/2022','/AB9847654 completed')
Select *
,ABValue = substring(notes,nullif(patindex('%AB[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',notes),0),10)
from #YourTable
Results
ServiceDate notes ABValue
9/1/2022 The order was called in AB13456736 AB13456736
9/1/2022 AB45876453 not setup AB45876453
9/2/2022 Signature for AB764538334 AB76453833
9/2/2022 Contact for A0943847432 NULL
9/3/2022 Hold off on AB73645298 AB73645298
9/5/2022 ** Confirmed AB88988476 AB88988476
9/6/2022 /AB9847654 completed NULL
I have model I created on the fly for peewee. Something like this:
class TestTable(PeeweeBaseModel):
whencreated_dt = DateTimeField(null=True)
whenchanged = CharField(max_length=50, null=True)
I load data from a text file to a table using peewee, the column "whenchanged" contains all dates in a format of '%Y-%m-%d %H:%M:%S' as varchar column. Now I want to convert the text field "whenchanged" into a datetime format in "whencreated_dt".
I tried several things... I ended up with this:
# Initialize table to TestTable
to_execute = "table.update({table.%s : datetime.strptime(table.%s, '%%Y-%%m-%%d %%H:%%M:%%S')}).execute()" % ('whencreated_dt', 'whencreated')
which fails with a "TypeError: strptime() argument 1 must be str, not CharField": I'm trying to convert "whencreated" to datetime and then assign it to "whencreated_dt".
I tried a variation... following e.g. works without a hitch:
# Initialize table to TestTable
to_execute = "table.update({table.%s : datetime.now()}).execute()" % (self.name)
exec(to_execute)
But this is of course just the current datetime, and not another field.
Anyone knows a solution to this?
Edit... I did find a workaround eventually... but I'm still looking for a better solution... The workaround:
all_objects = table.select()
for o in all_objects:
datetime_str = getattr( o, 'whencreated' )
setattr(o, 'whencreated_dt', datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S'))
o.save()
Loop over all rows in the table, get the "whencreated". Convert "whencreated" to a datetime, put it in "whencreated_dt", and save each row.
Regards,
Sven
Your example:
to_execute = "table.update({table.%s : datetime.strptime(table.%s, '%%Y-%%m-%%d %%H:%%M:%%S')}).execute()" % ('whencreated_dt', 'whencreated')
Will not work. Why? Because datetime.strptime is a Python function and operates in Python. An UPDATE query works in database-land. How the hell is the database going to magically pass row values into "datetime.strptime"? How would the db even know how to call such a function?
Instead you need to use a SQL function -- a function that is executed by the database. For example, Postgres:
TestTable.update(whencreated_dt=whenchanged.cast('timestamp')).execute()
This is the equivalent SQL:
UPDATE test_table SET whencreated_dt = CAST(whenchanged AS timestamp);
That should populate the column for you using the correct data type. For other databases, consult their manuals. Note that SQLite does not have a dedicated date/time data type, and the datetime functionality uses strings in the Y-m-d H:M:S format.
while executing this query i am getting error
UPDATE treedetailsentered
set geom_line=st_geomfromtext('LineString(('||longitude||' '||latitude||','||lon2||' '||lat2||'))', 4326);
error
ERROR: parse error - invalid geometry
HINT: "LineString((7" <-- parse error at position 13 within geometry
********** Error **********
this is how i created column in table for the linestring
ALTER TABLE public.treedetailsentered
ADD COLUMN geom_line geometry(LineString, 4326)
It's hard to tell what the exact problem is without knowing what type longitude, latitude have, but my guess is that you're not forming a proper string.
My advice is to debug this by first creating a proper text via a query that's simpler:
select 'LineString(('||longitude||' '||latitude||','||lon2||' '||lat2||'))'
Depending on what types you have, you might have to do some conversions, like this:
select 'LineString(('||longitude::text||' '||latitude::text||','||lon2::text||' '||lat2::text||'))'
If you already have texts, make sure that the numbers are properly formatted. Floats are expected to have a dot decimal separator for example.
I have added an extra bracket i removed that it worked for me.
UPDATE treedetailsentered set geom_line=ST_GeomFromText('LINESTRING(' || longitude || ' '||latitude||','||lon2||' '||lat2||')', 4326);
I've got a table full of WKT (well known text) in a varchar(max) column. This is formatted exactly as geometry. So, for example, one of the values is:
POLYGON ((174.893529167059 -37.0260462162965,174.89351593407 -37.0260221329151,174.893508034056 -37.0260077002766,174.893444415879 -37.0258916500588,174.893416916056 -37.0258414997842,174.893481733297 -37.0258186834198,174.893492016755 -37.0258150663863,174.89349653254 -37.025823316032,174.893512415978 -37.0258522827285,174.893556883897 -37.0259333832477,174.893591032956 -37.0259956661343,174.893604265986 -37.0260197504078,174.893575149738 -37.0260300006258,174.893529167059 -37.0260462162965))
However, I need to convert this varchar(max) field into a geometry field. Unfortunately, SQL Server needs to have some other information in order to do this, so I can't just change the type of the field from varchar(max) to geometry.
I've created a blank geometry column in the same table (MyGeometry) but I'm failing in trying to convert it. Here is my code (where 2193 is the CRS I'm dealing with). WKT is my varchar(max) field and MyGeometry is my new geometry field.
UPDATE MY_TABLE
SET MyGeometry = geometry::STPolyFromText('' + WKT + '', 2193)
EDIT - currently coming back saying the WKT is not valid (System.FormatException 24111 - the input isn't valid).
Which is strange as it matches up perfectly with some other inputs I have in how it's styled.
This will do :
UPDATE MY_TABLE
SET MyGeometry = geometry::STGeomFromText('POLYGON ((174.893529167059 -37.0260462162965,174.89351593407 -37.0260221329151,174.893508034056 -37.0260077002766,174.893444415879 -37.0258916500588,174.893416916056 -37.0258414997842,174.893481733297 -37.0258186834198,174.893492016755 -37.0258150663863,174.89349653254 -37.025823316032,174.893512415978 -37.0258522827285,174.893556883897 -37.0259333832477,174.893591032956 -37.0259956661343,174.893604265986 -37.0260197504078,174.893575149738 -37.0260300006258,174.893529167059 -37.0260462162965))', 0)
You can change that 'POLYGON....' to your VARCHAR(MAX) field.
0 at the end, which is SRID only relevant if you're using Geography.
You can also try :-
UPDATE MY_TABLE SET MyGeometry = GEOMETRY::STGeomFromText('POLYGON ((174.893529167059 -37.0260462162965,174.89351593407 -37.0260221329151,174.893508034056 -37.0260077002766,174.893444415879 -37.0258916500588,174.893416916056 -37.0258414997842,174.893481733297 -37.0258186834198,174.893492016755 -37.0258150663863,174.89349653254 -37.025823316032,174.893512415978 -37.0258522827285,174.893556883897 -37.0259333832477,174.893591032956 -37.0259956661343,174.893604265986 -37.0260197504078,174.893575149738 -37.0260300006258,174.893529167059 -37.0260462162965))',4326);
The value of SRID passed should be 4326 and not 0
You can check the URL below. I found this information in another similar question (older post) so pasting it without any changes
I found solution, SQL Server Spatial Tools
http://sqlspatialtools.codeplex.com/
Followings are the methods solved my problem.
IsValidGeographyFromText(string inputWKT, int srid)
Check if an input WKT can represent a valid geography. This function requires that the WTK coordinate values are longitude/latitude values, in that order and that a valid geography SRID value is supplied. This function will not throw an exception even in edge conditions (i.e. longitude/latitude coordinates are reversed to latitude/longitude).
SqlGeography MakeValidGeographyFromText(string inputWKT, int srid)
Convert an input WKT to a valid geography instance. This function requires that the WKT coordinate values are longitude/latitude values, in that order and that a valid geography SRID value is supplied.
I'm having an issue with SQL Server 2008 and the geometry functions. I'm trying to create non-overlapping shapes using the STDifference function... but it does not seem to be working 100% of the time.
Here is all the sample code to demonstrate the issue. Anybody have any idea to make these non-overlapping polygons? (except "don't make your polygons so complex")
-- create our Geometry polygons.
DECLARE #Geo1 Geometry, #Geo2 Geometry;
SET #Geo1 = geometry::STGeomFromText('POLYGON ((-79725887.5234375 42951274.765625, -79699548.921875 42991827.84375, -79695546.375697568 42997990.498925969, -79695559.967852488 42998690.733179785, -79696152.0625 43029192.375, -79715247.75 43051708.75, -79802181.8984375 43020797.71875, -79806253.6640625 43018621.6953125, -79810436.03125 43014767.046875, -79825837.5 43000572.375, -79830640.625 42973672.03125, -79832936.7265625 42960812.4296875, -79725887.5234375 42951274.765625))',0);
SET #Geo2 = geometry::STGeomFromText('POLYGON ((-79863430.6875 42937209.4375, -79850399.0625 42940068.75, -79850394.9375 42940069.625, -79845320.6875 42946082.625, -79843216.25 42948576.375, -79832949.125 42960743, -79814909.939453125 43061773.556640625, -79817218.30078125 43060262.947265625, -79823496.6875 43056154.3125, -79867800.5 43027161.5625, -79871834.50390625 43024521.70703125, -79875660.228515625 43022018.123046875, -79875666.8125 43022013.8125, -79875674.536313191 43022008.760254942, -79875676.408203125 43022007.53515625, -79875677.236328125 43022006.994140625, -79875718.458984375 43021980.017578125, -79875728.506891936 43021973.442301653, -79881723.017578125 43018050.58984375, -79882437.0625 43017583.3125, -79882585.375 43017486.25, -79884466.9375 43016254.9375, -79884550.875 43016200, -79886514.3125 43014915.125, -79887785.5 43014083.25, -79887790.4375 43014080, -79887793.125 43014078.26953125, -79887807.171875 43014069.076171875, -79887825.568359375 43014057.03515625, -79887831.322335 43014053.269705132, -79888029.5 43013923.5625, -79890094.5625 43012572.1875, -79934236.875 42983685.125, -79863430.6875 42937209.4375))',0);
-- A quick test so you can see them
SELECT #Geo1, 'Geo1' as MyName UNION ALL SELECT #Geo2, 'Geo2' as MyName;
-- how do they compare initially?
SELECT
#Geo1.STTouches(#Geo2) as 'Touches'
,#Geo1.STOverlaps(#Geo2) as 'Overlaps'
,#Geo1.STIntersects(#Geo2) as 'Intersects'
-- try to make them NOT overlap or intersect
SET #Geo1 = #Geo1.STDifference(#Geo2);
SET #Geo2 = #Geo2.STDifference(#Geo1);
-- Now, how do they compare?
SELECT
#Geo1.STTouches(#Geo2) as 'Touches'
,#Geo1.STOverlaps(#Geo2) as 'Overlaps'
,#Geo1.STIntersects(#Geo2) as 'Intersects'
-- what does the intersection look like?
SELECT #Geo1.STIntersection(#Geo2).STAsText();
This is the final select result:
MULTIPOLYGON (((-79831832.015625 42966999.5078125, -79830502.34765625 42974446.45703125, -79830181.430394545 42976243.79133676, -79830220.96484375 42976022.375, -79831832.015625 42966999.5078125)), ((-79832481.0538819 42963364.484146826, -79832328.75390625 42964217.45703125, -79831832.015625 42966999.5078125, -79832481.0538819 42963364.484146826)))
Not an answer, just an observation... I get different results if I introduce two new variables for the two differences.
-- create our Geometry polygons.
DECLARE #Geo1 Geometry, #Geo2 Geometry, #Geo3 Geometry, #Geo4 Geometry;
SET #Geo1 = geometry::STGeomFromText('POLYGON ((-79725887.5234375 42951274.765625, -79699548.921875 42991827.84375, -79695546.375697568 42997990.498925969, -79695559.967852488 42998690.733179785, -79696152.0625 43029192.375, -79715247.75 43051708.75, -79802181.8984375 43020797.71875, -79806253.6640625 43018621.6953125, -79810436.03125 43014767.046875, -79825837.5 43000572.375, -79830640.625 42973672.03125, -79832936.7265625 42960812.4296875, -79725887.5234375 42951274.765625))',0);
SET #Geo2 = geometry::STGeomFromText('POLYGON ((-79863430.6875 42937209.4375, -79850399.0625 42940068.75, -79850394.9375 42940069.625, -79845320.6875 42946082.625, -79843216.25 42948576.375, -79832949.125 42960743, -79814909.939453125 43061773.556640625, -79817218.30078125 43060262.947265625, -79823496.6875 43056154.3125, -79867800.5 43027161.5625, -79871834.50390625 43024521.70703125, -79875660.228515625 43022018.123046875, -79875666.8125 43022013.8125, -79875674.536313191 43022008.760254942, -79875676.408203125 43022007.53515625, -79875677.236328125 43022006.994140625, -79875718.458984375 43021980.017578125, -79875728.506891936 43021973.442301653, -79881723.017578125 43018050.58984375, -79882437.0625 43017583.3125, -79882585.375 43017486.25, -79884466.9375 43016254.9375, -79884550.875 43016200, -79886514.3125 43014915.125, -79887785.5 43014083.25, -79887790.4375 43014080, -79887793.125 43014078.26953125, -79887807.171875 43014069.076171875, -79887825.568359375 43014057.03515625, -79887831.322335 43014053.269705132, -79888029.5 43013923.5625, -79890094.5625 43012572.1875, -79934236.875 42983685.125, -79863430.6875 42937209.4375))',0);
-- A quick test so you can see them
SELECT #Geo1, 'Geo1' as MyName UNION ALL SELECT #Geo2, 'Geo2' as MyName;
-- how do they compare initially?
SELECT
#Geo1.STTouches(#Geo2) as 'Touches'
,#Geo1.STOverlaps(#Geo2) as 'Overlaps'
,#Geo1.STIntersects(#Geo2) as 'Intersects'
-- try to make them NOT overlap or intersect
SET #Geo3 = #Geo1.STDifference(#Geo2);
SET #Geo4 = #Geo2.STDifference(#Geo1);
-- Now, how do they compare?
SELECT
#Geo3.STTouches(#Geo4) as 'Touches'
,#Geo3.STOverlaps(#Geo4) as 'Overlaps'
,#Geo3.STIntersects(#Geo4) as 'Intersects'
-- what does the intersection look like?
SELECT #Geo3.STIntersection(#Geo4).STAsText();
Compare:
Touches Overlaps Intersects
1 0 1
Final Select:
MULTIPOINT ((-79830220.96484375 42976022.375), (-79831832.015625 42966999.5078125))
I suspect this is due to the method/precision with which SQL Server performs spatial calculations. For operations like STIntersection() etc, SQL Server rounds the supplied float coordinate values to a 27 bit integer grid. This can introduce slight distortions to the coordinates returned as the result of spatial operations.
In your case, your coordinate values are large, which means that the fixed size integer grid must be made quite coarse to accommodate the full range of data. The relative difference between the intersecting coordinates that you're trying to remove, however, is very small. When snapped to this coarse grid, SQL Server is unable to correctly identify the area of intersection.
See here for a explanation, and also a suggestion that this situation has been improved in SQL Server Denali:
https://connect.microsoft.com/SQLServer/feedback/details/580254/spatial-operations-are-done-with-a-low-precision-causing-troubles-in-the-returned-data
As pointed out by Joe Stefanelli, your polygons don't technically overlap but they do intersect. The reason is that if you cut a hole out of one polygon using a smaller polygon, the smaller polygon will not overlap the new polygon but it will intersect it along the edge of the cut. It isn't like a table saw that removes some material along the edge of the cut. I could not include the code because SO is having a problem with certain SQL statements and blocks the post.
SEE REFERENCE A in image
If you would like it not to overlap OR intersect, you can create your own sawblade effect. Apply a very small buffer around the smaller of the geometries when using it in the STDifference() function.
SEE REFERENCE B in image
I know this post is old but it does seem pertinent still for those of us who will still be on 2008 for a while.