Top 5 Recent Articles
ARTICLES CATEGORIES
- Algorithms (22)
- All (399)
- Biography (1)
- Blog (44)
- Business Requirements (1)
- Commentary (1)
- Conversion (2)
- Customers (2)
- Data Models (1)
- Education (2)
- GeoRaptor (13)
- GPS (1)
- Image Processing (2)
- Import Export (8)
- Licensing (2)
- LiDAR (1)
- Linear Referencing (4)
- Manifold GIS (3)
- Mapping (1)
- MySQL Spatial (7)
- Networking and Routing (including Optimization) (5)
- Open Source (18)
- Oracle Spatial and Locator (194)
- Partitioning (1)
- PostGIS (36)
- Projections (1)
- Published Articles (1)
- qGIS (1)
- Recommendations (1)
- Services (1)
- Software Change Log (1)
- Source Code (37)
- Space Curves (9)
- Spatial Database Functions (109)
- Spatial DB comparison (1)
- Spatial XML Processing (11)
- SQL Server Spatial (92)
- Standards (3)
- Stored Procedure (17)
- Tessellation or Gridding (10)
- Tools (2)
- Topological Relationships (1)
- Training (2)
- Triangulation (2)
Scheduling the Export of Spatial Data in Oracle to a Shapefile each night
While there is always a need for software like Safe Software’s Awesome FME to automate import and export tasks from your database, the ability to do so just using Oracle can also be enormously useful.
I have implemented the approach described below many times over the years, in different customer sites.
At one customer site, there was a requirement for the engineers to be able to access the latest version of the corporate spatial data stored in Oracle within their own dedicated desktop software. Some of that software could access Oracle directly, but some couldn’t. Additionally, the engineers needed to be able to take the data into the field where no connection to the database was possible.
Luckily their software could access shapefiles or MapInfo TAB files (even those which wrap a shapefile).
Additionally, spatial data within databases is often undergoing such editing that makes it difficult to enable direct access at any time of the day.
The obvious solution was to use Oracle Scheduled Tasks to export that critical engineering asset data each night to a shared drive. This approach provides security to end-users that they are working with the latest “published” version of the data (as different from the current version in the database that may still be undergoing editing). It also implements a level of robustness and reliability that is not possible when one is forced to use software external to the database and probably running on a completely different server.
Certainly the engineers and foresters that have benefited from these scheduled exports were happy with the idea!
But how do so it?
Well the Oracle Scheduler is easy enough to learn, but how can Oracle write formats that it does not directly support within the database?
(GeoJSON can be exported because most databases today support JSON and the ability to write/load data from disk.)
But Spatial to a Shapefile?
As I have said above one can use FME for this but not as a completely native Oracle process.
The solution I created uses my EXPORTER package which uses Java code (based on Java Topology Suite, GeoTools etc) to create the solution. The Java code is created, compiled and then loaded into the Oracle database JVM. The EXPORTER PL/SQL Package creates an interface which PL/SQL based processes can use. The EXPORTER Package supports ESRI Shapefiles, Wrapped TAB files, Excel Spreadsheets, Delimited Text Files (eg CSV) and soon GeoJSON.
Since I have been tidying up, improving, testing, and adding the GeoJSON functionality to the Java on which is based my EXPORTER code, I thought I would create an fully worked article on the exporting of sdo_geometry data to a shapefile via DBMS_SCHEDULER.
The EXPORTER package is available on my website. The new improved and expanded code will be re-leased soon as part of a whole package of tested software that will be bundled for purchase.
Here is an example of exporting data in a table called SEWER_PIT to a shapefile.
DROP TABLE Sewer_Pit PURGE; TABLE SEWER_PIT dropped. . CREATE TABLE Sewer_Pit ( AssetId INTEGER, Pit_Label varchar2(20), Pit_Lid_Material varchar2(10), Pit_Diameter NUMBER, Pit_Depth NUMBER, geom mdsys.sdo_geometry ); TABLE SEWER_PIT created. . SET FEEDBACK OFF INSERT INTO Sewer_Pit (AssetId, Pit_Label, Pit_Lid_Material, Pit_Diameter, Pit_Depth, geom) SELECT rownum AS AssetId, CHR(dbms_random.VALUE(65,90)) || to_char(round(dbms_random.VALUE(0,1000),0),'FM9999') AS Pit_Label, CASE WHEN round(dbms_random.VALUE(0,1),0) = 0 THEN 'Concrete' ELSE 'Plastic' END AS Pit_Lid_Material, CASE WHEN round(dbms_random.VALUE(0,1),0) = 0 THEN 900 ELSE 1200 END AS Pit_Diameter, ROUND(dbms_random.VALUE(0.5,15.0),1) AS Pit_Depth, mdsys.sdo_geometry(3001, 28355, MDSYS.SDO_POINT_TYPE( ROUND(DBMS_RANDOM.VALUE( 300000, 500000),3), ROUND(DBMS_RANDOM.VALUE(5000000,5500000),3), ROUND(DBMS_RANDOM.VALUE( -50, 1500),2)), NULL,NULL) FROM DUAL CONNECT BY LEVEL <= 500 COMMIT SET FEEDBACK ON SET HEADING OFF . SELECT 'Inserted '||COUNT(*)||' records into Sewer_Pit' FROM Sewer_Pit Inserted 500 records INTO Sewer_Pit . 1 ROWS selected . SET HEADING ON DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = UPPER('Sewer_Pit'); 1 ROWS deleted. . COMMIT; committed. . DECLARE v_shape mdsys.sdo_geometry; BEGIN SELECT SDO_AGGR_MBR(geom) INTO v_shape FROM Sewer_Pit; INSERT INTO USER_SDO_GEOM_METADATA(TABLE_NAME,COLUMN_NAME,DIMINFO,SRID) VALUES (UPPER('Sewer_Pit'), 'GEOM', MDSYS.SDO_DIM_ARRAY( MDSYS.SDO_DIM_ELEMENT('X',V_SHAPE.SDO_ORDINATES(1),V_SHAPE.SDO_ORDINATES(4),0.05), MDSYS.SDO_DIM_ELEMENT('Y',V_SHAPE.SDO_ORDINATES(2),V_SHAPE.SDO_ORDINATES(5),0.05), MDSYS.SDO_DIM_ELEMENT('Z',V_SHAPE.SDO_ORDINATES(3),V_SHAPE.SDO_ORDINATES(6),0.05)), 28355); END; / SHOW ERRORS anonymous block completed No Errors. . COMMIT; committed. . CREATE INDEX Sewer_Pit_GEOM ON Sewer_Pit(geom) INDEXTYPE IS mdsys.spatial_index parameters('sdo_indx_dims=2, layer_gtype=point'); INDEX SEWER_PIT_GEOM created. . BEGIN -- Note use of Aliases to make column names > 10 characters Dbase compliant DBMS_SCHEDULER.CREATE_JOB ( job_name ='ASSET_DATA_EXPORT', job_type ='PLSQL_BLOCK', job_action =' DECLARE BEGIN EXPORTER.writeshapefile( p_sql =''SELECT ASSETID,PIT_LABEL,PIT_LID_MATERIAL as Lid_Mtrl,PIT_DIAMETER as diameter,PIT_DEPTH,GEOM FROM PROJPOINT2D'', p_output_dir =''C:\temp'', p_file_name =''points_night_extract'', p_shape_type =EXPORTER.c_Point, p_geometry_index =6, p_precision =3, p_commit_interval =100, p_prj_string =''PROJCS["GDA94 / MGA zone 56",GEOGCS["GDA94",DATUM["D_GDA_1994",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",153],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",10000000],UNIT["Meter",1]]'', p_geomFormat =EXPORTER.c_WKT_Format, p_recordIdentifier=''GID'' ); END;', start_date =to_timestamp(trunc(sysdate+1))+5/24, repeat_interval ='freq=weekly; byday=mon,tue,wed,thu,fri; byhour=5; byminute=0; bysecond=0', comments ='Job to export sewer_pits for use with Civil Software every working day at 5am.' ); END; / SHOW ERRORS anonymous block completed No Errors. . -- Enable the job EXEC DBMS_SCHEDULER.ENABLE('ASSET_DATA_EXPORT'); anonymous block completed . -- Show the job SELECT job_name, job_type, schedule_type, start_date, Repeat_interval, Enabled, Run_Count, job_action FROM USER_SCHEDULER_JOBS; . -- Results edited and split across two lines... -- JOB_NAME JOB_TYPE SCHEDULE_TYPE START_DATE REPEAT_INTERVAL ENABLED RUN_COUNT ------------------------------- ------------- -------------------------------------- ---------------------------------------------------------------------------- ------- --------- ASSET_DATA_EXPORT PLSQL_BLOCK CALENDAR 06-SEP-18 05.00.00.000000000 AM AUSTRA freq=weekly; byday=mon,tue,wed,thu,fri; byhour=5; byminute=0; bysecond=0 TRUE 0 . JOB_ACTION ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- DECLARE BEGIN EXPORTER.writeshapefile( p_sql ='SELECT ASSETID,PIT_LABEL,PIT_LID_MATERIAL,PIT_DIAMETER,PIT_DEPTH,GEOM FROM PROJPOINT2D', p_output_dir ='C:\temp', p_file_name ='points_night_extract', p_shape_type =EXPORTER.c_Point, p_geometry_index =6, p_precision =3, p_commit_interval =100, p_prj_string ='PROJCS["GDA94 / MGA zone 56",GEOGCS["GDA94",DATUM["D_GDA_1994",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",153],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",10000000],UNIT["Meter",1]]', p_geomFormat =EXPORTER.c_WKT_Format, p_recordIdentifier='GID' ); END; . 1 ROWS selected . -- Drop the job EXECUTE DBMS_SCHEDULER.DROP_JOB (job_name => 'ASSET_DATA_EXPORT'); anonymous block completed . -- Confirm job is gone. SELECT * FROM USER_SCHEDULER_JOBS no ROWS selected
Now this is of use to everybody working in a similar situation to that which caused this work to be done!
Documentation
- MySQL Spatial General Functions
- Oracle LRS Objects
- Oracle Spatial Exporter (Java + pl/SQL)
- Oracle Spatial Object Functions
- Oracle Spatial Object Functions (Multi Page)
- PostGIS pl/pgSQL Functions
- SC4O Oracle Java Topology Suite (Java + pl/SQL)
- SQL Server Spatial General TSQL Functions
- SQL Server Spatial LRS TSQL Functions