web-dev-qa-db-fra.com

Impossible d'identifier l'opérateur d'égalité de type json [] lors de l'utilisation de UNION

J'essaie d'exécuter plusieurs requêtes sur une même table à l'aide d'une règle UNION

J'ai deux tables:

  • projet (id, nom, BOOLEAN épinglé)
  • compétences (m2m aux projets)

Je cherche d'abord à obtenir un tableau de lignes qui ont pinned défini sur true et remplir le reste avec les dernières entrées (pinned défini sur false)

SELECT
  project.id AS project_id,
  project.name AS project_name,
  array_agg(json_build_object('skill_id', project_skills.id,'name', project_skills.skill)) AS skills
from project
LEFT OUTER JOIN project_skills on project.name = project_skills.project
WHERE project.pinned = true
GROUP BY project_id,project_name

UNION

SELECT
  project.id AS project_id,
  project.name AS project_name,
  array_agg(json_build_object('skill_id', project_skills.id,'name', project_skills.skill)) AS skills
from project
LEFT OUTER JOIN project_skills on project.name = project_skills.project
WHERE project.id != 1 AND project.pinned = false
GROUP BY project_id,project_name
ORDER BY project.create_date DESC LIMIT 5

Lors de l'exécution de cette requête, j'obtiens l'erreur ci-dessous

ERROR:  could not identify an equality operator for type json[]
LINE 7:   array_agg(json_build_object('skill_id', project_skills.id,...

Je ne comprends pas cette erreur. Est-ce qu'il échoue parce qu'il essaie de comparer les colonnes json des deux résultats?

J'utilise Postgres 9.4.

25
Kannaj

Lorsque vous utilisez un UNION, le SGBD supprime toutes les lignes en double et, pour ce faire, il doit identifier si deux lignes sont égales/identiques. Cela signifie à son tour regarder chaque colonne des deux lignes qu'il compare et décider si elles sont égales.

Le message d'erreur que vous voyez est celui où une de vos colonnes est construite à l'aide de array_agg(json_build_object(...)) qui produit une valeur de type json[], Ce qui signifie "tableau de valeurs json". Parce que Postgres ne sait pas comparer deux tableaux de valeurs JSON, il ne peut pas décider si votre UNION a produit des doublons.

Si vous ne vous souciez pas vraiment de supprimer les doublons, la solution la plus simple consiste à utiliser UNION ALL Qui ignore cette étape.

Comme indiqué dans les commentaires, si vous voulez supprimer les doublons, vous pouvez convertir les valeurs en quelque chose qui a un opérateur de comparaison défini. La solution la plus générale consiste à transtyper en texte (par exemple some_value::text Ou CAST(some_value as text)) mais pour JSON spécifiquement vous voulez probablement le type jsonb , qui ignorera le formatage lors de la comparaison.

Vous pouvez convertir json en jsonb, ou json[] En jsonb[], Ou dans cet exemple, vous pouvez créer jsonb directement avec la fonction array_agg(jsonb_build_object(...)) plutôt que array_agg(json_build_object(...)).

47
IMSoP

Il s'avère que tout ce que j'avais à faire était d'utiliser UNION ALL - je suppose que cela ignore la comparaison des types json entre les requêtes.

3
Kannaj