SQL Server 2008

Neue Datentypen

Kelly Wilson

 

Kurz zusammengefasst:

  • Neue Datums- und Uhrzeitdatentypen
  • Darstellen der Position in einer Hierarchie
  • Zwei Modelle für die Arbeit mit räumlichen Daten

Um in der globalen Wirtschaft Geschäfte machen zu können, müssen Unternehmen zunehmend neue Datentypen, Anwendungen und komplexe Berechnungen einsetzen. Die sieben neuen in SQL Server 2008 integrierten Datentypen

ermöglichen die Arbeit mit komplizierteren Daten und vereinfachen deren Verwaltung.

Datum und Uhrzeit

Bei dem alten Datentyp „datetime“ hatten SQL Server®-Benutzer keine Möglichkeit, mit den Datums- und Uhrzeitangaben separat zu arbeiten. Vier der neuen Datentypen (date, time, datetime2 und datetimeoffset) ändern diese Situation, indem sie die Arbeit mit Datums- und Zeitangaben vereinfachen und einen größeren Datumsbereich, eine Genauigkeit von Sekundenbruchteilen sowie Zeitzonenunterstützung bieten. Neue Datenbankanwendungen sollten statt des herkömmlichen Datentyps „datetime“ diese neuen Datentypen verwenden. Betrachten wir die neuen Versionen etwas genauer.

Der Datentyp „date“ speichert ein Datum ohne Uhrzeitkomponente. Der Datumsbereich erstreckt sich vom 1. Januar 1000 bis zum 31. Dezember 9999 („0001-01-01“ bis „9999-12-31“). Jede Datumsvariable beansprucht 3 Byte im Speicher und besitzt eine Genauigkeit von 10 Stellen. Die Genauigkeit des Datentyps „date“ ist auf einen einzigen Tag beschränkt.

Betrachten Sie Abbildung 1, die zeigt, wie Datumsvariable in T-SQL-Skripts erstellt und initialisiert werden. Die Variable „@myDate1“ wird durch eine Zeichenfolge mit dem Format „MM/TT/JJJJ“ initialisiert. Die Variable „@myDate2“ wird nicht initialisiert, sondern hat den Wert NULL. Die Variable „@myDate3“ wird mit dem Datum des lokalen Computersystems initialisiert. Der Wert von Variablen kann jederzeit mit SELECT- oder SET-Anweisungen geändert werden, wie das Beispiel einer Änderung des Werts von @myDate2 veranschaulicht. Spalten des Typs „date“ können ebenfalls in Tabellen erstellt werden. Abbildung 2 zeigt, wie eine Tabelle mit drei date-Spalten erstellt wird.

Figure 2 Erstellen einer Tabelle mit drei date-Spalten

USE TempDB
GO

CREATE TABLE myTable
(
    myDate1 date,myDate2 date,myDate3 date
)
GO

INSERT INTO myTable
VALUES('01/22/2005',
       '2007-05-08 12:35:29.1234567 +12:15',
       GetDate())

SELECT * FROM myTable

--Results
--myDate1    myDate2    myDate3
------------ ---------- ----------
--2005-01-22 2007-05-08 2007-11-20

Figure 1 Erstellen und Initialisieren von Datumsvariablen in T-SQL-Skripts

DECLARE @myDate1 date = '01/22/2005'
DECLARE @myDate2 date
DECLARE @myDate3 date = GetDate()

SELECT @myDate2 = '2007-05-08 12:35:29.1234567 +12:15'

SELECT @myDate1 AS '@myDate1',
       @myDate2 AS '@myDate2',
       @myDate3 AS '@myDate3'

--Results
--@myDate1   @myDate2   @myDate3
------------ ---------- ----------
--2005-01-22 2007-05-08 2007-11-20

Der Datentyp „time“ speichert die Tageszeit ohne Datumskomponente. Da er auf dem 24-Stunden-Format basiert, unterstützt er einen Bereich von 00:00:00.0000000 bis 23:59:59.9999999 (Stunden, Minuten, Sekunden und Sekundenbruchteile). Beim Erstellen dieses Datentyps können Sie seine Genauigkeit in Sekundenbruchteilen festlegen. Dieser Datentyp besitzt eine Standardgenauigkeit von 7 Stellen bzw. 100 Nanosekunden. Die Genauigkeit wirkt sich darauf aus, wie viel Speicherplatz benötigt wird, und bewegt sich im Bereich von 3 Byte für bis zu 2 Stellen über 4 Byte für 3 oder 4 Stellen bis hin zu 5 Byte für 5 bis 7 Stellen.

Das in Abbildung 3 dargestellte T-SQL-Skript zeigt, wie sich implizite Konvertierungen eines Zeichenfolgeninitialisierungswerts auf die variable Genauigkeit auswirken. Der T-SQL-Code erstellt zunächst acht separate Uhrzeitvariable und initialisiert sie mit einem identischen Wert. Die Sekundenbruchteilgenauigkeit jeder Variablen lässt sich aus ihrem Namen ableiten. So bietet beispielsweise die Variable „@myTime3“ eine Sekundenbruchteilgenauigkeit von drei Stellen. Die Ergebnisse zeigen, dass die Genauigkeit jedes Uhrzeitdatentyps der Sekundenbruchteilgenauigkeit entspricht, mit der der Datentyp deklariert wird. Stellen, die außerhalb dieses Bereichs liegen, werden abgeschnitten.

Figure 3 Anzeigen der variablen Genauigkeit des Datentyps „time“

DECLARE @myTime  time = '01:01:01.1234567 +01:01'
DECLARE @myTime1 time(1) = '01:01:01.1234567 +01:01'
DECLARE @myTime2 time(2) = '01:01:01.1234567 +01:01'
DECLARE @myTime3 time(3) = '01:01:01.1234567 +01:01'
DECLARE @myTime4 time(4) = '01:01:01.1234567 +01:01'
DECLARE @myTime5 time(5) = '01:01:01.1234567 +01:01'
DECLARE @myTime6 time(6) = '01:01:01.1234567 +01:01'
DECLARE @myTime7 time(7) = '01:01:01.1234567 +01:01'

SELECT @myTime  AS '@myTime',
       @myTime1 AS '@myTime1',
       @myTime2 AS '@myTime2',
       @myTime3 AS '@myTime3',
       @myTime4 AS '@myTime4',
       @myTime5 AS '@myTime5',
       @myTime6 AS '@myTime6',
       @myTime7 AS '@myTime7'

--Results
--@myTime          @myTime1   @myTime2    @myTime3     @myTime4      
------------------ ---------- ----------- ------------ -------------
--01:01:01.1234567 01:01:01.1 01:01:01.12 01:01:01.123 01:01:01.1235
--
--@myTime5       @myTime6        @myTime7
---------------- --------------- ----------------
--01:01:01.12346 01:01:01.123457 01:01:01.1234567

DROP TABLE myTable

Ein time-Datentyp kann als Spalte in einer Tabelle erstellt werden. Das T-SQL-Skript „DROP TABLE myTable“ in Abbildung 4 erstellt eine Tabelle namens „myTable1“ und fügt ihr drei time-Spalten hinzu. Danach wird ein Datensatz in die Tabelle eingefügt, und es werden durch eine SELECT-Anweisung die Inhalte der Tabelle angezeigt.

Figure 4 Erstellen von myTable1

USE TempDB
GO

CREATE TABLE myTable1
(
    myTime1 time(1),
    myTime2 time(2),
    myTime3 time(3)
)
GO

INSERT INTO myTable1
VALUES('01:30:01.1234567',
       '02:34:01.1234567',
       '03:01:59.1234567')

SELECT * from myTable1

--Results
--myTime1    myTime2     myTime3
------------ ----------- ------------
--01:30:01.1000000 02:34:15.1200000 03:01:59.1230000

DROP TABLE myTable1

datetimeoffset und datetime2

Der Datentyp „datetimeoffset“ berücksichtigt Zeitzonen. Der Datentyp „time“ beinhaltet keine Zeitzone und arbeitet daher nur mit der Ortszeit. In der globalen Wirtschaft ist es jedoch oft notwendig zu wissen, wie sich eine Uhrzeit in einem bestimmten Teil der Welt zu einer Uhrzeit in einem anderen Teil der Welt verhält. Der Zeitunterschied wird im Format „+ hh:mm“ bzw. oder „- hh:mm“ angegeben.

Dieser Code erstellt eine Variable des Datentyps „datetimeoffset“ und initialisiert sie mit dem Uhrzeitwert „8:52 A.M. Pacific Standard Time“:

DECLARE @date DATETIMEOFFSET = '2007-11-26T08:52:00.1234567-08:00'
PRINT @date
--Results
--2007-11-26 08:52:00.1234567 -08:00

Die Zeichenfolge, die die Variable des Datentyps „datetimeoffset“ (im Skript: @date) initialisiert, besitzt ein spezielles Format, das in absteigender Reihenfolge zu Beginn das wichtigste und zum Schluss das am wenigsten wichtige Element angibt. Das Datumselement und das Uhrzeitelement werden durch einen einzelnen Großbuchstaben „T“ voneinander getrennt. Ein Minusvorzeichen trennt die Uhrzeitelemente von der Zeitzone. Zwischen dem Minuszeichen und der Uhrzeit- oder Zeitzonenangabe stehen keine Leerzeichen. Dieses Format ist eines von zwei ISO 8601-Formaten, die vom Datentyp „datetimeoffset“ unterstützt werden. (ISO 8601 ist eine internationale Norm zur Darstellung von Datums- und Uhrzeitwerten.)

Die Genauigkeit der Uhrzeitkomponente wird genau wie beim Datentyp „time“ angegeben, wobei als Standardwert die gleichen sieben Stellen verwendet werden, falls nichts angegeben wird. Der unterstützte Bereich ist identisch.

Der Datentyp „datetime2“ ist eine Erweiterung des ursprünglichen Datentyps „datetime“. Er unterstützt einen größeren Datumsbereich und eine höhere Sekundenbruchteilgenauigkeit und ermöglicht Ihnen, die Genauigkeit festzulegen. Der Datumsbereich des Datentyps „datetime2“ erstreckt sich vom 1. Januar 0001 bis zum 31. Dezember 9999, wohingegen der Datumsbereich des ursprünglichen Datentyps „datetime“ nur vom 1. Januar 1753 bis zum 31. Dezember 9999 reichte. Genau wie bei dem Datentyp „time“ wird eine Genauigkeit von siebenstelligen Sekundenbruchteilen bereitgestellt. Der ursprüngliche Datentyp „datetime“ bot eine dreistellige Genauigkeit und einen Uhrzeitbereich von 00:00:00 bis 23:59:59.999. Hier können Sie sehen, wie eine Variable des Datentyps „datetime2“ erstellt und mit dem Datum und der Uhrzeit des lokalen Servers initialisiert wird:

DECLARE @datetime2 DATETIME2 = GetDate();
PRINT @datetime2

--Results
--2007-11-26 09:39:04.1370000

Als Nächstes werde ich den neuen Datentyp „hierarchyid“ untersuchen. Dieser Datentyp arbeitet nicht mit einer bestimmten Datums- oder Uhrzeitangabe, sondern mit der Beziehung zwischen Datenelementen in einer Tabelle.

Der Datentyp „hierarchyid“

Mit dem Datentyp „hierarchyid“ können Sie Beziehungen zwischen Datenelementen innerhalb einer Tabelle erstellen, was vor allem dem Zweck dient, eine Position innerhalb einer Hierarchie darzustellen. Um diesen Datentyp zu untersuchen, erstelle ich zunächst mit dem Skript in Abbildung 5 die MyCompany-Datenbank und fülle sie mit Mitarbeiterdaten.

Figure 5 Erstellen und Füllen der MyCompany-Datenbank

USE MASTER
GO

CREATE DATABASE MyCompany
GO
USE MyCompany
GO

--Create a table called employee that will store
--the data for the employees for MyCompany.
    
CREATE TABLE employee
(
    EmployeeID int NOT NULL,
    EmpName    varchar(20) NOT NULL,
    Title      varchar(20) NULL,
    Salary     decimal(18, 2) NOT NULL,
    hireDate   datetimeoffset(0) NOT NULL,
)
GO

--These statements will insert the data for the employees of MyCompany.

INSERT INTO employee
VALUES(6,   'David',  'CEO', 35900.00, '2000-05-23T08:30:00-08:00')

INSERT INTO employee
VALUES(46,  'Sariya', 'Specialist', 14000.00, '2002-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(271, 'John',   'Specialist', 14000.00, '2002-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(119, 'Jill',   'Specialist', 14000.00, '2007-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(269, 'Wanida', 'Assistant', 8000.00, '2003-05-23T09:00:00-08:00')

INSERT INTO employee
VALUES(272, 'Mary',   'Assistant', 8000.00, '2004-05-23T09:00:00-08:00')
GO
--Results
--EmployeeID  EmpName Title      Salary   hireDate
------------- ------- ---------- -------- --------------------------
--6           David   CEO        35900.00 2000-05-23 08:30:00 -08:00
--46          Sariya  Specialist 14000.00 2002-05-23 09:00:00 -08:00
--271         John    Specialist 14000.00 2002-05-23 09:00:00 -08:00
--119         Jill    Specialist 14000.00 2007-05-23 09:00:00 -08:00
--269         Wanida  Assistant  8000.00  2003-05-23 09:00:00 -08:00
--272         Mary    Assistant  8000.00  2004-05-23 09:00:00 -08:00

Abbildung 6 zeigt die sich ergebende einfache Datenbank, die aus einer einzigen Mitarbeitertabelle besteht. Diese Mitarbeitertabelle in der MyCompany-Datenbank besitzt keine auferlegte Struktur. Dies ist bei einer relationalen Datenbank normal, denn eine Struktur wird auf dynamische Weise von einer Anwendung durch ihren Abfrage- und Verarbeitungscode auferlegt.

Abbildung 6 Die MyCompany-Mitarbeitertabelle

Abbildung 6** Die MyCompany-Mitarbeitertabelle **

Geschäftsdaten dagegen besitzen in der Regel eine inhärente Struktur. So gibt es beispielsweise in jedem Unternehmen eine Struktur aus Vorgesetzten und Untergebenen wie z. B. die Struktur, die in Abbildung 7 für MyCompany dargestellt ist. Alle Mitarbeiter von MyCompany sind Untergebene des Geschäftsführers David. Einige Mitarbeiter wie z. B. Jill sind seine direkten Untergebenen. Andere Mitarbeiter wie z. B. Mary sind seine indirekten Untergebenen, da eine Mittelsperson dazwischen steht, die ihr direkter Vorgesetzter ist. In der Programmierung wird die hierarchische Struktur von MyCompany als Baumstruktur bezeichnet, weil sie einem Baum ähnelt. David an der Spitze hat keinen Vorgesetzten. Er ist das übergeordnete Element bzw. Vorgängerelement. Die Mitarbeiter, deren Vorgesetzter David ist, sind unter ihm angeordnet. Derartige Knoten werden als untergeordnete Elemente oder Nachfolgerelemente bezeichnet. David kann so viele Nachfolger wie nötig besitzen, um seine direkten Untergebenen darzustellen.

Abbildung 7 Die Organisationsstruktur von MyCompany

Abbildung 7** Die Organisationsstruktur von MyCompany **(Klicken Sie zum Vergrößern auf das Bild)

Das Skript in Abbildung 8 baut die MyCompany-Datenbank unter Verwendung des Datentyps „hierarchyid“ neu auf und erstellt dabei eine Beziehung, die der hierarchischen Struktur von MyCompany entspricht. Zunächst wird mit der ALTER TABLE-Anweisung eine Spalte des Typs „hierarchyid“ hinzugefügt. Danach wird mit der hierarchyid-Methode „GetRoot“ der Knoten „David“ eingefügt. Anschließend werden mit der Methode „GetDescendant“ die direkten Untergebenen von David der Baumstruktur hinzugefügt.

Figure 8 Neuaufbau der Datenbank mithilfe des hierarchyid-Typs

DELETE employee
GO
ALTER TABLE employee ADD OrgNode hierarchyid NOT NULL
GO

DECLARE @child hierarchyid,
@Manager hierarchyid = hierarchyid::GetRoot()

--The first step is to add the node at the top of the
--tree. Since David is the CEO his node will be the
--root node.

INSERT INTO employee
VALUES(6,   'David',  'CEO', 35900.00,
       '2000-05-23T08:30:00-08:00', @Manager)

--The next step is to insert the records for
--the employees that report directly to David.

SELECT @child = @Manager.GetDescendant(NULL, NULL)

INSERT INTO employee
VALUES(46,  'Sariya', 'Specialist', 14000.00,
       '2002-05-23T09:00:00-08:00', @child)

SELECT @child = @Manager.GetDescendant(@child, NULL)
INSERT INTO employee
VALUES(271, ‚John',   ‚Specialist', 14000.00,
       '2002-05-23T09:00:00-08:00', @child)

SELECT @child = @Manager.GetDescendant(@child, NULL)
INSERT INTO employee
VALUES(119, ‚Jill',   ‚Specialist', 14000.00,
       ‚2007-05-23T09:00:00-08:00', @child)

--We can now insert the employee that reports to
--Sariya.
SELECT @manager = OrgNode.GetDescendant(NULL, NULL)
FROM employee WHERE EmployeeID = 46

INSERT INTO employee
VALUES(269, ‚Wanida', ‚Assistant', 8000.00,
       ‚2003-05-23T09:00:00-08:00', @manager)

--Next insert the employee that report to John.
SELECT @manager = OrgNode.GetDescendant(NULL, NULL)
FROM employee WHERE EmployeeID = 271

INSERT INTO employee
VALUES(272, ‚Mary',   ‚Assistant', 8000.00,
       ‚2004-05-23T09:00:00-08:00', @manager)
GO

Sobald die Datenbankdatensätze hinzugefügt wurden und die Hierarchie erstellt wurde, können die Inhalte der Mitarbeitertabelle mit einer Abfrage wie der folgenden angezeigt werden:

SELECT EmpName, Title, Salary, OrgNode.ToString() AS OrgNode
FROM employee ORDER BY OrgNode
GO
--Results
--EmpName  Title      Salary    OrgNode
---------- ---------- --------- -------
--David    CEO        35900.00  /
--Sariya   Specialist 14000.00  /1/
--Wanida   Assistant  8000.00   /1/1/
--John     Specialist 14000.00  /2/
--Mary     Assistant  8000.00   /2/1/
--Jill     Specialist 14000.00  /3/

OrgNode ist die Spalte des Typs „hierarchyid“. Im Ergebnis wird durch jeden Schrägstrich ein Knoten in der Hierarchiestruktur angegeben. David befindet sich am Stamm, was durch einen einzelnen Schrägstrich angezeigt wird. Sariya, John und Jill sind Untergebene von David und besitzen zwei Schrägstriche, wodurch angegeben wird, dass sie in der Hierarchie den zweiten Knoten bilden. Die Zahlen 1, 2 oder 3 geben die Reihenfolge des jeweiligen untergeordneten Knotens an. Dieses System ist sehr flexibel. Untergeordnete Knoten können nach Bedarf entfernt, eingefügt oder hinzugefügt werden. Wenn ich beispielsweise zwischen John und Jill einen Mitarbeiter hinzufügen würde, würde dieser Mitarbeiter im Resultset folgendermaßen aufgelistet werden: /2.1/.

Wenn Sie beispielsweise die Antwort auf die Frage „Wer ist ein Untergebener von Sariya?“ ermitteln möchten, können Sie dazu die folgende T-SQL-Code-Abfrage erstellen:

DECLARE @Sariya hierarchyid

SELECT @Sariya = OrgNode
FROM employee WHERE EmployeeID = 46

SELECT EmpName, Title, Salary, OrgNode.ToString() AS 'OrgNode'
FROM employee
WHERE OrgNode.GetAncestor(1) = @Sariya
GO
--Results
--EmpName Title     Salary  OrgNode
--------- --------- ------- -------
--Wanida  Assistant 8000.00 /1/1/

Die Abfrage verwendet die hierarchyid-Methode „GetAncestor“, die den übergeordneten Knoten des aktuellen hierarchyid-Knotens zurückgibt. Im vorherigen Code wird die Variable „@Sariya“ auf den Hierarchieknoten für Sariya gesetzt. Der Grund dafür ist, dass Sariya das direkte Vorgängerelement jedes Mitarbeiters ist, der ein Untergebener von ihr ist. Daher muss beim Schreiben einer Abfrage, von der die Mitarbeiter zurückgegeben werden sollen, die direkte Untergebene von Sariya sind, der Knoten von Sariya aus der Baumstruktur abgerufen werden, und es müssen anschließend alle Mitarbeiter ausgewählt werden, deren Vorgängerknoten der Knoten von Sariya ist.

Spalten des Typs „hierarchyid“ neigen dazu, sehr kompakt zu sein, weil die Anzahl der Bits, die dafür benötigt werden, einen Knoten in der Baumstruktur darzustellen, von der durchschnittlichen Anzahl der untergeordneten Elemente des Knotens (oft als „Fanout“ des Knotens bezeichnet) abhängt. So würde beispielsweise ein neuer Knoten in einer Organisationshierarchie von 100.000 Mitarbeitern mit einem durchschnittlichen Fanout von sechs Ebenen einen Speicherplatz von mehr als fünf Byte beanspruchen.

Der Datentyp „hierarchyid“ stellt mehrere Methoden bereit, die die Arbeit mit hierarchischen Daten vereinfachen. Eine Zusammenfassung dieser Methoden ist in Abbildung 9 zu sehen. Ausführliche Informationen zu allen Methoden stehen in der SQL Server-Onlinedokumentation (msdn2.microsoft.com/ms130214) zur Verfügung.

Figure 9 Vom Datentyp „hierarchyid“ bereitgestellte Methoden

Methode Beschreibung
GetAncestor Gibt einen hierarchyid-Knoten zurück, der das n-te Vorgängerelement dieses hierarchyid-Knotens repräsentiert.
GetDescendant Gibt einen untergeordneten Knoten dieses hierarchyid-Knotens zurück.
GetLevel Gibt eine Ganzzahl zurück, die die Tiefe dieses hierarchyid-Knotens in der Gesamthierarchie repräsentiert.
GetRoot Gibt den hierarchyid-Stammknoten dieser Hierarchiestruktur zurück. Statisch.
IsDescendant Gibt „true“ zurück, wenn der übergebene untergeordnete Knoten ein Nachfolgerelement dieses hierarchyid-Knotens ist.
Parse Konvertiert eine Zeichenfolgendarstellung einer Hierarchie in einen hierarchyid-Wert. Statisch.
Reparent Verschiebt einen Knoten einer Hierarchie innerhalb der Hierarchie an eine neue Position.
ToString Gibt eine Zeichenfolge zurück, die die logische Darstellung dieses hierarchyid-Werts enthält.

Räumliche Datentypen

Räumliche Daten sind Daten, die geografische Orte und Formen v. a. auf der Erde beschreiben. Bei diesen Orten und Formen kann es sich um Orientierungspunkte im Gelände, Straßen oder sogar den Standort eines Unternehmens handeln. Für die Arbeit mit dieser Art von Daten stellt SQL Server 2008 die Datentypen „geography“ und „geometry“ bereit.

Der Datentyp „geography“ arbeitet mit Daten des Globusmodells. Das Globusmodell berücksichtigt bei seinen Berechnungen, dass die Oberfläche der Erde gekrümmt ist. Positionen werden durch Länge und Breite angegeben. Dieses Modell eignet sich gut für Anwendungen wie z. B. die Überseetransportschifffahrt und die militärische Planung sowie für Anwendungen, die sich auf kurze Distanzen auf der Erdoberfläche beziehen. Dieses Modell sollten Sie verwenden, wenn Ihre Daten in Form von Breiten- und Längengraden gespeichert sind.

Der Datentyp „geometry“ arbeitet nach dem planaren Modell einer flachen Welt. In diesem Modell wird die Erde als eine zweidimensionale Kartenabbildung behandelt, die von einem bekannten Punkt ausgeht. Das Flachweltmodell berücksichtigt die Krümmung der Erde nicht und wird deshalb in erster Linie zum Beschreiben kurzer Entfernungen verwendet, beispielsweise in einer Datenbankanwendung, die das Innere eines Gebäudes abbildet.

Die Datentypen „geography“ und „geometry“ werden aus Vektorobjekten erstellt und in den Formaten WKT (Well-Known Text) und WKB (Well-Known Binary) angegeben. Dies sind Übertragungsformate für räumliche Daten, die von der Spezifikation „Simple Features for SQL“ des OGC (Open Geospatial Consortium) beschrieben werden. In Abbildung 10 sind die sieben Arten von Vektorobjekten aufgelistet, die von SQL Server 2008 unterstützt werden.

Figure 10 Von SQL Server 2008 unterstützte Vektorobjekte

Objekt Beschreibung
Point Ein Ort.
MultiPoint Eine Reihe von Punkten.
LineString Eine Reihe von null oder mehr Punkten, die durch Linien verbunden sind.
MultiLineString Ein Satz von LineStrings.
Polygon Ein durch einen Satz geschlossener LineStrings beschriebener zusammenhängender Bereich.
MultiPolygon Ein Satz von Polygonen.
GeometryCollection Eine Sammlung von geography-Typen.

Um einen geography-Typ mit einem oder mehreren Vektorobjekten zu erstellen, müssen Sie zunächst, wie in Abbildung 11 gezeigt, den geography-Typ in Ihrem T-SQL Skript deklarieren. Danach rufen Sie eine der in Abbildung 12 aufgelisteten Methoden auf und übergeben ihr die Zeichenfolge für Ihr Vektorobjekt und die SRID (Spatial Reference ID). Die SRID ist das räumliche Referenzidentifikationssystem, das von der European Petroleum Survey Group definiert wurde. Die SRID ist Teil einer Gruppe von Normen, die für die Kartografie, die Vermessung und die Speicherung geodätischer Daten entwickelt wurde. Jede SRID beschreibt eine bestimmte Art von Ellipsoid, der in geographischen Berechnungen verwendet wird. Dies ist notwendig, da die Erde keine perfekte Kugel ist. SQL Server 2008 kann nur anhand identischer SRIDs Berechnungen durchführen.

Figure 12 Konstruieren von Objekten für „geography“ und „geometry“

Methode Beschreibung
STGeomFromText Erstellt aus dem Eingabetext eine geography-Instanz beliebigen Typs.
STPointFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „Point“.
STMPointFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „MultiPoint“.
STLineFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „LineString“.
STMLineFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „MultiLineString“.
STPolyFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „Polygon“.
STMPolyFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „MultiPolygon“.
STGeomCollFromText Erstellt aus dem Eingabetext eine geography-Instanz des Typs „GeometryCollection“.

Figure 11 Erstellen von Punkten, Linien und Polygongeometrie

DECLARE @geo1 geometry
SELECT @geo1 = geometry::STGeomFromText('POINT (3 4)', 0)
PRINT @geo1.ToString()

DECLARE @geo2 geometry
SELECT @geo2 = geometry::Parse('POINT(3 4 7 2.5)')
PRINT @geo2.STX;
PRINT @geo2.STY;
PRINT @geo2.Z;
PRINT @geo2.M;

DECLARE @geo3 geography;
SELECT @geo3 = geography::STGeomFromText(
    'LINESTRING(47.656 -122.360, 47.656 -122.343)', 4326);
SELECT @geo3.ToString();

--Results
--POINT (3 4)
--3
--4
--7
--2.5

DECLARE @gx geometry; 
SET @gx = geometry::STPolyFromText(
    'POLYGON ((5 5, 10 5, 10 10, 5 5))', 0);
PRINT @gx.ToString();
--Results
--POLYGON ((5 5, 10 5, 10 10, 5 5))

Unterschiede zwischen den Datentypen „geography“ und „geometry“

Da die Datentypen „geography“ und „geometry“ für die Arbeit mit unterschiedlichen Arten von Daten vorgesehen sind, unterscheiden sie sich in einigen Punkten, über die Sie sich im Klaren sein müssen. Beim Datentyp „geometry“ werden Entfernungen und Flächen in derselben Maßeinheit wie die Koordinaten der Instanzen angegeben. So beträgt beispielsweise die Entfernung zwischen den Punkten (0,0) und (6,8) immer 10 Einheiten. Dies ist beim Datentyp „geography“ nicht der Fall, denn dieser Datentyp arbeitet mit ellipsoiden Koordinaten, die in Form von Breiten- und Längengraden ausgedrückt werden.

Der Datentyp „geometry“ gibt unsinnige Ergebnisse zurück, wenn Koordinaten als Paare aus Breiten- und Längengrad angegeben werden. Der folgende T-SQL-Code berechnet die Entfernung zwischen den Punkten (90 0) und (90 180). Da sich beide Punkte auf den Nordpol beziehen, müsste die Entfernung zwischen ihnen 0 Einheiten betragen. Im Fall des Datentyps „geometry“ wird jedoch eine Entfernung von 180 Einheiten errechnet.

DECLARE @g1 GEOMETRY, @g2 GEOMETRY, @g3 GEOGRAPHY, @g4 GEOGRAPHY
SELECT @g1 = GEOMETRY::STGeomFromText('POINT (90 0)', 0)
SELECT @g2 = GEOMETRY::STGeomFromText('POINT (90 180)', 0)

SELECT @g3 = GEOGRAPHY::STGeomFromText('POINT (90 0)', 4326)
SELECT @g4 = GEOGRAPHY::STGeomFromText('POINT (90 180)', 4326)
SELECT @g2.STDistance(@g1) AS 'GEOMETRY',
       @g4.STDistance(@g3) AS 'GEOGRAPHY';

--Results
--GEOMETRY               GEOGRAPHY
------------------------ ----------------------
--180                    0

Auch in der Orientierung räumlicher Daten besteht zwischen den beiden Datentypen ein Unterschied. Im planaren System, das vom Datentyp „geometry“ verwendet wird, ist die Orientierung des Polygons kein wesentlicher Faktor. So ist beispielsweise ein Polygon mit den Koordinaten ((0, 0), (10, 0), (0, 20), (0, 0)) identisch mit dem Polygon ((0, 0), (0, 20), (10, 0), (0, 0)). In dem vom Datentyp „geography“ verwendeten Datenmodell dagegen ist ein Polygon ohne Angabe einer Orientierung eine unklare Sache. Denken Sie zum Beispiel an einen Ring um den Äquator. Bezieht sich das durch diesen Ring beschriebene Polygon auf die nördliche oder die südliche Hemisphäre? Der springende Punkt hierbei ist, dass bei der Arbeit mit Daten des Datentyps „geography“ die Orientierung und die Position genau beschrieben werden müssen.

Dem Datentyp „geography“ werden auch von SQL Server 2008 einige Einschränkungen auferlegt. So muss beispielsweise jede geography-Instanz in eine einzige Hemisphäre passen. Größere räumliche Objekte sind nicht erlaubt und lösen einen ArgumentException-Fehler aus. geography-Datentypen, die zwei Eingaben erfordern, geben NULL zurück, wenn die Ergebnisse der Methoden nicht in eine einzige Hemisphäre passen.

SQL Server stellt mehrere Methoden bereit, die es ermöglichen, Operationen für geography- und geometry-Instanzen durchzuführen. Abbildung 13 zeigt einige Beispiele für die Verwendung von Methoden, die von SQL Server 2008 für die Arbeit mit räumlichen Daten bereitgestellt werden. Aus Platzgründen kann ich auf dieses Thema nicht ausführlicher eingehen, aber Sie können vollständige Beschreibungen in der SQL Server-Onlinedokumentation finden.

Figure 13 Arbeiten mit räumlichen Daten

DECLARE @gm geometry;
DECLARE @gg geography;
DECLARE @h geography;

SET @gm = geometry::STGeomFromText('POLYGON((0 0, 13 0, 3 3, 0 13, 0 0),(2 2, 2 1, 1 1, 1 2, 2 2))', 0);
SELECT @gm.STArea();

--Results
--38

SET @gg = geography::STGeomFromText('LINESTRING(0 0, 5 5)', 4326);
--Calculate the distance to a point slightly offset from the LINESTRING.
SET @h = geography::STGeomFromText('POINT(4 4)', 4326);
SELECT @gg.STDistance(@h);

--Results
-- 430.182777043046

--Calculate the distance to a point on the LINESTRING.
SET @h = geography::STGeomFromText('POINT(5 5)', 4326);
SELECT @gg.STDistance(@h);

--Results
-- 0

DECLARE @temp table ([name] varchar(10), [geom] geography);

INSERT INTO @temp values ('Point', geography::STGeomFromText('POINT(
5 10)', 4326));
INSERT INTO @temp values ('LineString', geography::STGeomFromText(
'LINESTRING(13 5, 50 25)', 4326));
--Calculate the distance to a point on the LINESTRING.
--Display the number of dimensions for a geography object stored in a --table variable.
INSERT INTO @temp values ('Polygon', geography::STGeomFromText(
'POLYGON((47.653 -122.358, 47.649 -122.348, 47.658 -122.348, 47.658 -122.358, 47.653 -122.358))', 4326));

SELECT [name], [geom].STDimension() as [dim]
FROM @temp;

--Results
--name       dim
------------ -----------
--Point      0
--LineString 1
--Polygon    2

Ich hoffe, dass diese Informationen zu den sieben neuen Datentypen in SQL Server 2008 hilfreich waren.

Kelly Wilson ist seit über 20 Jahren im Bereich des Software Engineering tätig. Während dieser Zeit hat sie Anwendungen für SQL Server, 3D-Grafik-Programme, Spiele und Anwendungen im Bereich der Farbwissenschaft geschrieben. Kelly Wilson arbeitet derzeit als Programming Writer in der SQL Server-Gruppe bei Microsoft.

© 2008 Microsoft Corporation und CMP Media, LLC. Alle Rechte vorbehalten. Die nicht genehmigte teilweise oder vollständige Vervielfältigung ist nicht zulässig.