11. Oktober 2007

Auf den Ort kommt es an: Geodaten in der Datenbank!

Wie dem einen oder anderen vielleicht bekannt ist, kann die Oracle-Datenbank auch Geodaten speichern. Dazu gibt es mit SDO_GEOMETRY sogar einen eigenen Datentyp. So repräsentiert ...
SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(11.57917, 48.13842, NULL), NULL, NULL)
... die Lokation des Marienplatzes in München. Diese Geodaten-Funktionalität wird übrigens recht verbreitet genutzt; so nutzen die meisten Geodaten-Systeme Oracle als darunterliegende Datenbank. Neben dem einfachen Speichern werden natürlich auch Operationen auf den Geodaten angeboten - Distanzberechnungen, das Finden der nächsten Nachbarn oder andere räumliche Operationen sind mit den Funktionen des PL/SQL-Pakets SDO_GEOM kein Problem - Als Beispiel soll die Datenbank mal berechnen, wie weit es vom Reichstag in Berlin zum Marienplatz ist ...
select 
  sdo_geom.sdo_distance(
    SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(11.57917, 48.13842, NULL), NULL, NULL),
    SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(13.45742, 52.58146, NULL), NULL, NULL),
    1
  ) as entfernung_luftlinie
from dual;


ENTFERNUNG_LUFTLINIE
--------------------
    511930.915008963

1 Zeile wurde ausgewählt.
... also ca. 511km (Luftlinie). Solche Geometrien können nun natürlich einfach zusammen mit Fachdaten in einer Tabelle gespeichert werden - dies sähe dann in etwa so aus:
create table meine_kunden(
  id             number(10),
  name           varchar2(200),
  lokation       sdo_geometry
  :
)
/
In diesem Zusammenhang kam neulich eine Frage auf mich zu: Wie kann man, wenn man von einem bekannten Punkt ausgeht, die Himmelsrichtung eines anderen Punktes bestimmen?. Dazu bietet die Datenbank leider keine eingebaute Funktion an - ist aber zum Glück recht einfach selbst zu implementieren ...
create or replace function getAngle(
  p1 sdo_geometry,
  p2 sdo_geometry
) return number
is
  v_dx number;
  v_dy number;
  v_distance number;

  v_angle number;
begin
  v_dx := p2.sdo_point.x - p1.sdo_point.x;
  v_dy := p2.sdo_point.y - p1.sdo_point.y;

  v_distance := sqrt(v_dx * v_dx + v_dy * v_dy);
  v_angle := acos(v_dy / v_distance) * 360 / 6.28;
  if v_dx < 0 then v_angle := -v_angle; end if; 
  return v_angle;
end;
/
sho err
Probiert man diese neue Funktion nun aus, dann ergibt sich ...
select
  getangle(
    SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(11.57917, 48.13842, NULL), NULL, NULL),
    SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(13.45742, 52.58146, NULL), NULL, NULL)
  ) as winkel
from dual

    WINKEL
----------
22,9273402

1 Zeile wurde ausgewählt.
... und aus dem Winkel lässt sich recht leicht die Himmelsrichtung ableiten - dies hier wäre dann etwa Nord-Nordost

Mehr Interesse am Thema Geodaten in der Datenbank ... ? Dann einfach was in den Kommentar schreiben. Übrigens: Man muss nicht unbedingt die Spatial-Option lizensieren, um die Geodaten-Funktionen nutzen zu können. Die hier vorgestellten Dinge (und mehr) sind komplett in der Standard-Edition enthalten.

Kommentare:

Anonym hat gesagt…

Geo-Daten und Spatial sind ein sehr interessantes Thema! Viele von denjenigen, den es rudimentär bekannt ist, wissen aber nicht, daß man für die Grundlagen der Spatial-Funktionalität keine zusätzlichen Lizenzkosten zahlen muß.

Hier wäre es vielleicht einmal seitens Oracle angebracht, klarer darzustellen, welche Funktionen man "umsonst" nutzen kann; sicherlich würde damit das Interesse an Spatial steigern.

Carsten Czarski hat gesagt…

Eins ist richtig: Die Information, welche Funktionen im Locator (keine zusätzlichen Lizenzkosten) und welche in der Spatial Option (Lizenzkosten) enthalten ist, ist ein wenig versteckt ...

Überblick: Spatial (Option) vs. Locator (Standard-Edition)
Kapitel aus der Oracle-Dokumentation mit genauen Hinweisen zu im Locator (keine zusätzlichen Kosten) enthaltenen Funktionalität

Anonym hat gesagt…

Was ist hierbei nun der Ausgangspunkt?

Also wenn ich die Koordinaten verkehrt herum in die Funktion gebe, dann bekomme ich einen Winkel von 157,163958462134. Un dies ergäbe dann ~Süd Ost.

Das Problem hierbei ist aber dass weder München noch Berlin (egal welcher der beiden als Ausgangspkt genommen wird) in dieser Himmelsrichtung zueinander stehen

Carsten Czarski hat gesagt…

Hallo ...

danke für das Feedback; die Funktion unterschlägt in der Tat eine wichtige Information ... das Vorzeichen. Die 157° sind schon richtig, aber nur, wenn man sie mit einem (-) versieht. Ich habe eine Zeile eingebaut, welche das Vorzeichen wieder richtig setzt. Der Ausgangspunkt ist damit immer der erste angegebene Punkt.

Viele Grüße

-Carsten

Anonym hat gesagt…

Meiner Meinung nach fehlt dann aber noch eine Besonderheit die behandelt werden müßte, nämlich wenn die X-Koordinaten identisch sind (sprich die beiden Point untereinander liegen), hierbei muss dann auch unterschieden werden ob 180° oder 360° zutreffen?!

mfg
Markus alias Anonym von vorhin (sollte mich hier mal anmelden)

Carsten Czarski hat gesagt…

naja, im Moment gibt es entweder °0, wenn der zweite Y-Wert größer ist, der Punkt also nördlich liegt, ist der zweite Y-Wert kleiner, dann liegt der Wert südlich - die Funktion gibt 180,091299° zurück (Rundungsfehler) - passt m.E. nach alles soweit ...

... und wenn die Punkte ewakt aufeinanderliegen (X und Y-Werte gleich) dann gibt es im Moment noch eine Fehlermeldung:

FEHLER in Zeile 2:
ORA-01476: divisor is equal to zero
ORA-06512: at "SCOTT.GETANGLE", line 16

könnte man noch abfangen und SQL NULL oder eine andere Fehlermeldung zurückgeben ...

Also mir schein die Funktion soweit zu passen ...

Viele Grüße

-Carsten

Anonym hat gesagt…

Habs grad selbst ausprobiert und nehme mein vorherhiges Kommentar zurück (hätte die Theorie testen solln, bevor ich den Mund aufmache).

mfg
Markus

Beliebte Postings