I live in Ohio which is fairly stable as far as earthquakes go; but I have coworkers and friends that live in other, more quake-prone areas of the country. So, sometimes I like to look up what’s going on in those areas. Naturally, I decided to see how I could use Oracle features to assist in my monitoring.
First, I needed a reliable source of information. The U.S. Geological Survey web site is my data source and they have a variety of free data feeds available. If you’re going to do a lot of data analysis I recommend pulling the data into a local table and saving it rather than hammering their server again and again for each query.
So, while these example show how to access and parse the data, your production use should be to local storage. You’ll get better performance on repeated access rather than pulling across the internet anyway.
The USGS has a several different formats available. I’ll be using the Quakeml formatted feed. Quakeml is simply xml with a predefined schema. Since I’m not a seismologist I’m only interested in the basic information of when?/where?/how big? and not necessarily all of the minute details like sampling method, uncertainty, etc.
In the examples below I’ll use a rectangular box to define the area I want to examine and I’ll request all of the data for the current and previous 2 days. For more complete information on constructing other query urls, see the reference here: http://earthquake.usgs.gov/fdsnws/event/1
The service returns a single xml document consisting of multiple event tags. Each event represents one earthquake. We’ll extract the text within the following nodes to get our result set.
/q:quakeml/eventParameters/event/description/text
/q:quakeml/eventParameters/event/origin/time/value
/q:quakeml/eventParameters/event/origin/longitude/value
/q:quakeml/eventParameters/event/origin/latitude/value
/q:quakeml/eventParameters/event/origin/depth/value
/q:quakeml/eventParameters/event/magnitude/mag/value
Note text is an xml tag, not the xquery function text().
The url construction requires some cumbersome syntax but isn’t really all that complicated. It basically boils down to a base url followed by the parameters for the start and end times (in GMT), a boundary box of latitude/longitude coordinates, a minimum magnitude and an ordering criteria.
In this case I’m looking for a bounding box that includes the state of Oklahoma, thus yielding a url construction of:
'http://earthquake.usgs.gov/fdsnws/event/1/query.quakeml?starttime='
|| TO_CHAR(FROM_TZ(CAST(TRUNC(SYSDATE - 2) AS TIMESTAMP), 'US/Eastern') AT TIME ZONE 'GMT', 'yyyy-mm-dd')
|| '&endtime='
|| TO_CHAR(SYSTIMESTAMP AT TIME ZONE 'GMT', 'yyyy-mm-dd"%20"hh24:mi:ss')
|| '&maxlatitude=37&minlatitude=33&maxlongitude=-94&minlongitude=-103'
|| '&minmagnitude=0&orderby=time'
Using the HTTPURITYPE function we can read the USGS site for that url and extract the xml. Using the XMLTABLE we can then extract each of the event nodes into individual rows and parse out the values we’re interested in.
SELECT FROM_TZ(TO_TIMESTAMP(time, 'yyyy-mm-dd"T"hh24:mi:ssxff"Z"'), 'GMT') AT TIME ZONE 'US/Central' quake_time, latitude, longitude, magnitude, depth_in_meters, location_name, XMLSERIALIZE(DOCUMENT eventxml AS CLOB INDENT SIZE = 3) FROM XMLTABLE( xmlnamespaces(DEFAULT 'http://quakeml.org/xmlns/bed/1.2', 'http://anss.org/xmlns/catalog/0.1' AS "catalog", 'http://quakeml.org/xmlns/quakeml/1.2' AS "q"), '/q:quakeml/eventParameters/event' PASSING httpuritype( 'http://earthquake.usgs.gov/fdsnws/event/1/query.quakeml?starttime=' || TO_CHAR(FROM_TZ(CAST(TRUNC(SYSDATE - 2) AS TIMESTAMP), 'US/Eastern') AT TIME ZONE 'GMT','yyyy-mm-dd"') || '&endtime=' || TO_CHAR(SYSTIMESTAMP AT TIME ZONE 'GMT', 'yyyy-mm-dd"%20"hh24:mi:ss') || '&maxlatitude=37&minlatitude=33&maxlongitude=-94&minlongitude=-103' || '&minmagnitude=0&orderby=time').getxml() COLUMNS eventxml XMLTYPE PATH '.', time VARCHAR2(100) PATH './origin/time/value', longitude NUMBER PATH './origin/longitude/value', latitude NUMBER PATH './origin/latitude/value', magnitude NUMBER PATH './magnitude/mag/value', depth_in_meters NUMBER PATH './origin/depth/value', location_name VARCHAR2(100) PATH './description/text')
Since Oklahoma is in US/Central timezone I’ll extract the data in time local to the events.
Running the query above yields a result set like the following…
QUAKE_TIME | LATITUDE | LONGITUDE | MAGNITUDE | DEPTH_IN_METERS | LOCATION_NAME |
---|---|---|---|---|---|
2015-07-27 19:24:03.770000000 -05:00 |
35.9938
|
-97.5664
|
3.2
|
3290
|
5km NNE of Crescent, Oklahoma |
2015-07-27 16:07:46.590000000 -05:00 |
36.0019
|
-97.5183
|
2.5
|
4490
|
8km NE of Crescent, Oklahoma |
2015-07-27 13:12:15.330000000 -05:00 |
36.006
|
-97.5761
|
4.5
|
3180
|
6km NNE of Crescent, Oklahoma |
2015-07-27 12:49:28.000000000 -05:00 |
36.0018
|
-97.5667
|
4
|
5590
|
6km NNE of Crescent, Oklahoma |
2015-07-26 08:26:50.480000000 -05:00 |
35.9983
|
-97.5693
|
3.2
|
4270
|
5km NNE of Crescent, Oklahoma |
2015-07-26 06:30:48.720000000 -05:00 |
36.5294
|
-98.8821
|
3
|
5000
|
30km ENE of Mooreland, Oklahoma |
2015-07-26 04:54:33.520000000 -05:00 |
36.0082
|
-97.5709
|
3.9
|
5860
|
6km NNE of Crescent, Oklahoma |
2015-07-26 04:15:06.100000000 -05:00 |
35.9656
|
-96.8124
|
2.8
|
4160
|
4km WSW of Cushing, Oklahoma |
2015-07-26 01:59:44.610000000 -05:00 |
36.0016
|
-97.5775
|
2.9
|
7130
|
5km NNE of Crescent, Oklahoma |
2015-07-25 06:14:44.200000000 -05:00 |
36.0034
|
-97.568
|
3.9
|
5570
|
6km NNE of Crescent, Oklahoma |
2015-07-25 03:47:53.420000000 -05:00 |
36.3478
|
-96.8192
|
2.9
|
1100
|
1km NW of Pawnee, Oklahoma |
2015-07-25 01:48:21.880000000 -05:00 |
36.136
|
-97.0685
|
1.8
|
4280
|
2km NNW of Stillwater, Oklahoma |
2015-07-24 23:49:02.820000000 -05:00 |
36.1675
|
-96.967
|
3
|
5000
|
10km NE of Stillwater, Oklahoma |
2015-07-24 23:10:33.690000000 -05:00 |
36.5804
|
-97.6208
|
3.1
|
5000
|
27km SSE of Medford, Oklahoma |