it-swarm.com.de

So konvertieren Sie den jsonb-Typ von PostgreSQL 9.4 in float

Ich versuche die folgende Abfrage:

SELECT (json_data->'position'->'lat') + 1.0 AS lat FROM updates LIMIT 5;

(Die +1.0 ist nur da, um die Konvertierung in Float zu erzwingen. Meine tatsächlichen Abfragen sind weitaus komplexer. Diese Abfrage ist nur ein Testfall für das Problem.)

Ich erhalte den Fehler:

ERROR:  operator does not exist: jsonb + numeric

Wenn ich explizites Casting hinzufüge:

SELECT (json_data->'position'->'lat')::float + 1.0 AS lat FROM updates LIMIT 5;

der Fehler wird:

ERROR:  operator does not exist: jsonb + double precesion

Ich verstehe, dass die meisten JSONB-Werte nicht in Floats umgewandelt werden können, aber in diesem Fall weiß ich, dass die Lats alle JSON-Zahlen sind.

Gibt es eine Funktion, die Jsonb-Werte in Floats umwandelt (oder NULL-Werte für das Uncastable zurückgibt)?

31
fadedbee

Es gibt zwei Operationen, um den Wert von JSON abzurufen. Der erste -> gibt JSON zurück. Der zweite ->> gibt Text zurück.

Details: JSON-Funktionen und -Operatoren

Versuchen

SELECT (json_data->'position'->>'lat')::float + 1.0 AS lat
FROM updates
LIMIT 5
80

Per Dokumentation gibt es auch die Funktionen

jsonb_populate_record()
jsonb_populate_recordset()

Analog zu ihren Json-Zwillingen (vorhanden seit S. 9.3)

json_populate_record()
json_populate_recordset()

Sie benötigen einen vordefinierten Zeilentyp. Verwenden Sie entweder den Zeilentyp einer vorhandenen Tabelle oder definieren Sie eine mit CREATE TYPE. Oder ersetzen Sie sie ad hoc durch eine temporäre Tabelle:

CREATE TEMP TABLE x(lat float);

Kann eine einzelne Spalte oder eine lange Liste von Spalten sein.

Es werden nur die Spalten gefüllt, in denen der Name mit einem Schlüssel in der Spalte übereinstimmt json Objekt. Der Wert wird in den Spaltentyp umgewandelt und muss kompatibel sein mit oder Es wird eine Ausnahme ausgelöst. Andere Schlüssel werden ignoriert.

SELECT lat + 1  -- no need for 1.0, this is float already
FROM   updates u
     , jsonb_populate_record(NULL::x, u.json_data->'position')
LIMIT  5;

Verwenden Sie hier ein implizites LATERAL JOIN .

Verwenden Sie auf ähnliche Weise jsonb_populate_recordset(), um Arrays in mehrere Zeilen pro Eintrag zu zerlegen.

Dies funktioniert genauso in Postgres 9.3 mit json. Es gibt den zusätzlichen Vorteil, dass für numerische Daten in text kein internes Casting nach/von jsonb erforderlich ist.

6

AFAIK, es gibt kein json-> float-Casting in Postgres, also könntest du es mit einem expliziten (json_data->'position'->'lat')::text::float Besetzung

5
knitti

Hinzufügen einer Klarstellung, da dies als Top-Treffer für eine Suche nach 'JSONB-Float-Konvertierung' angezeigt wird. Beachten Sie, dass Sie die JSON-Konvertierung in eckige Klammern setzen und dann das Casting '::' anwenden müssen.

Wie oben erwähnt, ist die richtige Methode:

(json_data #>> '{field}')::float

Wenn Sie dies stattdessen versuchen, schlägt dies fehl:

json_data #>> '{field}'::float

Dies war der Fehler, den ich in meinem Code gemacht habe, und es dauerte eine Weile, bis ich ihn sah - eine einfache Lösung, sobald ich es bemerkte.

3
rocksteady

Sie müssen den JSON-Wert in Text umwandeln und dann in Floating-Werte umwandeln.

Versuche dies:

(json_data #>> '{field}')::float
1
Luis Castillo