2017-09-19 4 views
1

J'utilise sqlalchemy sur une base de données postgres, et j'essaye de faire de l'arithmétique dans un SELECT sur deux champs JSON qui représentent des flottants. Cependant, je n'ai pas compris comment faire ce travail.sqlalchemy/postgres: arithmétique sur les champs JSON?

On suppose que je l'ai bien défini une table appelée transactions qui contient une colonne JSON appelée cost_data, et supposons que cette structure JSON contient deux attributs appelés cost et subtotal qui représentent les valeurs flottantes.

Dans une déclaration SELECT, je produis la somme de ces deux champs comme suit:

(cast(transactions.c.cost_data['subtotal'], sqlalchemy.Float) + cast(transactions.c.cost_data['cost'], sqlalchemy.Float)).label('total_cost') 

Cela génère le fragment SQL suivant ...

CAST((transactions.cost_data -> %(cost_data_6)s) AS FLOAT) + CAST((transactions.cost_data -> %(cost_data_7)s) AS FLOAT) AS total_cost 

(où cost_data_6 et cost_data_7 obtenir mis à subtotal et cost, respectivement).

Cependant, je reçois l'erreur suivante:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) cannot cast type json to double precision 

Si je retire la coulée et le faire comme suit, il échoue aussi ...

(transactions.c.cost_data['subtotal'] + transactions.c.cost_data['cost']).label('total_cost') 

Je reçois cette erreur ...

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) operator does not exist: json || json 
LINE 9: ... (transactions.cost_data -> 'subtotal') || (transa... 
               ^

de toute évidence, cela est parce que les champs sont disponibles en tant que chaînes, et l'opérateur « + » est interprété comme une chaîne concatenat ion.

De plus, si j'utilise l'opérateur Python float, il échoue aussi ...

(float(transactions.c.cost_data['subtotal']) + float(transactions.c.cost_data['cost'])).label('total_cost') 

L'interpréteur python n'exécute même pas le code, et il donne cette erreur:

TypeError: float() argument must be a string or a number, not 'BinaryExpression' 

Alors, comment puis-je effectuer l'ajout de ces deux champs en utilisant sqlalchemy?

PS: ce qui suit est une valeur de la colonne cost_data typique ...

{"cost":3.99,"subtotal":12.34} 
+0

Notez que l'argent et à virgule flottante peut-être un mauvais match. [Vous pouvez utiliser numérique à la place] (https://stackoverflow.com/questions/45689496/query-a-specific-json-column-postgres-with-sqlalchemy). –

+0

D'accord, en général. Dans ce cas, je ne suis pas en mesure de modifier les définitions des colonnes de la base de données, et d'autres logiciels utilisent des flottants pour ces champs. – HippoMan

Répondre

0

OK. J'ai finalement compris. Je dois passer chaque référence par l'opérateur astext avant d'appliquer cast comme suit ...

(transactions.c.cost_data['subtotal'].astext.cast(sqlalchemy.Float) + transactions.c.cost_data['cost'].astext.cast(sqlalchemy.Float)).label('total_cost')