Vergleich (json,xml, array)#

../../../_images/suprematismus04.webp

Ausgangsfrage#

Welche Datenstruktur ist geeignet, um Werte und Maßeinheiten in einer Datenbank zu speichern?

Es folgen einige Versuche mit dem Datentypen Array, JSON und XML. Betrachtet man andere Datenbank-Entwürfe, ist die klassische Antwort, eine Relation mit zwei Attributen, wobei die Dimension verschlüsselt wird. Ein Auszug aus dem ArcGis-Datenbankschema zeigt die Schlüsseldefinitionen:

Feldname

Feldtyp

Beschreibung

NULL?

sde_tpye

integer

Code für den Datentyp der Spalte;

mögliche Werte und ihre Definitionen sind:

1 = SE_INT16_TYPE – 2-Byte-Ganzzahl

2 = SE_INT32_TYPE – 4-Byte-Ganzzahl

3 = SE_FLOAT32_TYPE – 4-Byte-Gleitkommazahl

4 = SE_FLOAT64_TYPE – 8-Byte-Gleitkommazahl

5 = SE_STRING_TYPE – Null-Terminalzeichen-Array

6 = SE_BLOB_TYPE – Daten mit variabler Länge

7 = SE_DATE_TYPE – Uhrzeit/Datum strukturiert

8 = SE_SHAPE_TYPE – Shape-Geometrie (SE_SHAPE)

9 = SE_RASTER_TYPE – Raster

Klassischer Lösungsansatz#

  1. Der Wert wird gespeichert (Tabelle »messwerte«).

  2. Die Maßeinheit wird als Fremdschlüssel in einer separaten Relation (Tabelle »dimensionen«) nachgeschlagen.

    drop table if exists messwerte;
    create table messwerte (
      id bigint generated always as identity,
      wert decimal not null,
      dimension integer not null,
      werte_array text[],
      werte_json  json,
      werte_xml  xml
    );
    
    drop table if exists dimensionen;
    
    create table dimensionen (
      id bigint generated always as identity,
      wert text unique not null
    );
    
    
    insert into dimensionen (wert) values ('°C');
    insert into dimensionen (wert) values ('km/h');
    insert into dimensionen (wert) values ('t/ha');
    insert into dimensionen (wert)values ('kg');
    
    -- Wert und Dimenison in zwei Spalten
    
    insert into messwerte (wert, dimension) values (10,1);
    insert into messwerte (wert, dimension) values (100,2);
    insert into messwerte (wert, dimension) values (550.34,3);
    insert into messwerte (wert, dimension) values (120,4);
    
    -- JSON
    
    update messwerte set werte_json = '{"w": 10, "v": "°C"}' where id = 1;
    update messwerte set werte_json = '{"w": 100, "v": "km/h"}' where id = 2;
    update messwerte set werte_json = '{"w": 550.34, "v": "t/ha"}' where id = 3;
    update messwerte set werte_json = '{"w": 120, "v": "kg"}' where id = 4;
    
    -- xml
    
    update messwerte set werte_xml='<d><w>10</w><v>°C</v></d>' where id = 1;
    update messwerte set werte_xml='<d><w>100</w><v>km/h</v></d>' where id = 2;
    update messwerte set werte_xml='<d><w>550.34</w><v>t/ha</v></d>' where id = 3;
    update messwerte set werte_xml='<d><w>120</w><v>kg</v></d>' where id = 4;
    
    -- Array
    
    update messwerte set werte_array='{"10","°C"}' where id = 1;
    update messwerte set werte_array='{"100","km/h"}' where id = 2;
    update messwerte set werte_array='{"550.34","t/ha"}' where id = 3;
    update messwerte set werte_array='{"10","kg"}' where id = 4;
    

Ausgabe#

  Wert  |     halber Wert      | Dimension
--------+----------------------+----------
     10 |   5.0000000000000000 | °C
    100 |  50.0000000000000000 | km/h
 550.34 | 275.1700000000000000 | t/ha
    120 |  60.0000000000000000 | kg
(4 rows)

Alle nachfolgenden Speicher- und Extraktions-Varianten erzeugen das hier gezeigte Ergebnis.

Klassisch über beide Relationen#

select
  m.wert as Wert,
  m.wert/2 as "halber Wert",
  d.wert as Dimension
from  messwerte as m left join dimensionen as d
on dimension = d.id;

Liste aus Array#

select
  werte_array[1] as Wert,
  werte_array[1]::decimal/2 as "halber Wert" ,
  werte_array[2] as Dimension
from messwerte;

Liste aus JSON#

select
  werte_json->'w' as Wert,
  (werte_json->>'w')::decimal/2 as "halber Wert" ,
  werte_json->'v' as Dimension
from messwerte;

Liste aus XML#

select
  value::text::decimal as Wert,
  value::text::decimal / 2 as "halber Wert",
  dimension as "Dimension"
from  (select
         (xpath('/d/w/text()', werte_xml::xml))[1] as value,
         (xpath('/d/v/text()', werte_xml::xml))[1] as dimension
       from messwerte) as foo;

Bewertung#

  • Die komlexeste Abfrage wird für den XML-Datentyp benötigt.

  • Für alle Datentypen JSON, XML, Array gilt:

    Wenn das Zielsystem den gespeicherten Datentyp benötigt, können ohne Transformationsschritte die Rohdaten ausgeliefert werden.

  • Soll innerhalb der Datenbank auf einzelne Werte zugegriffen werden, sind der Array-Datentyp und die klassische Zwei-Tabellen-Version die empfehlenswerte Lösungen.