4 votes

Pourquoi PostgreSQL affiche "FULL JOIN is only supported with merge-joinable or hash-joinable join conditions" ?

J'essaie de joindre 2 tables avec une condition OR comme ceci :

FULL JOIN table1
     ON (replace(split_part(table1.contract_award_number::text, ' '::text, 2), '-'::text, ''::text)) = table2.contract_award_id 

     OR (btrim(replace(table1.solicitation_number::text, '-'::text, ''::text))) = table2.solicitation_id

Mais Postgresql m'aboie dessus avec :

FULL JOIN is only supported with merge-joinable or hash-joinable join conditions

Que se passe-t-il ? Pour une raison quelconque, si j'ajoute la condition :

WHERE table1.solicitation_number::text ~~ '%%'::text 

l'erreur ne se produit pas, mais je soupçonne que cela fausse le résultat du FULL JOIN.

Merci pour toute aide.

7voto

Tim Biegeleisen Points 53335

Il devrait être possible d'émuler toute jointure externe complète entre deux tables en utilisant la requête suivante :

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL

La première moitié de l'union obtient les enregistrements propres à la première table, ainsi que tous les enregistrements qui se chevauchent. La seconde moitié de l'union obtient les enregistrements propres à la seconde table uniquement. En appliquant ce modèle à votre requête, on obtient :

SELECT column1, column2, column3
FROM fpds_opportunities fpds
LEFT JOIN fbo_all_opportunity_detail fbo
    ON replace(split_part(fbo.contract_award_number::text, ' '::text, 2), 
               '-'::text, ''::text) = fpds.contract_award_id OR
       btrim(replace(fbo.solicitation_number::text, '-'::text, ''::text)) = fpds.solicitation_id
UNION ALL
SELECT column1, column2, column3
FROM fpds_opportunities fpds
RIGHT JOIN fbo_all_opportunity_detail fbo
    ON replace(split_part(fbo.contract_award_number::text, ' '::text, 2), 
               '-'::text, ''::text) = fpds.contract_award_id OR
       btrim(replace(fbo.solicitation_number::text, '-'::text, ''::text)) = fpds.solicitation_id
WHERE
    fpds.contract_award_id IS NULL AND fdps.solicitation_id IS NULL;

1voto

joop Points 3173

Vous pourriez précalculer les chaînes laides dans une sous-requête (ou CTE), et faire un JOIN avec cela. (cela semble également pratique pour construire et tester la requête ; on ne réussit jamais du premier coup ces chaînes de caractères ...)


SELECT ...
FROM table2
FULL JOIN (
        SELECT *
        , replace(split_part(table1.contract_award_number::text, ' '::text, 2), '-'::text, ''::text) AS xca
        , btrim(replace(table1.solicitation_number::text, '-'::text, ''::text)) AS xsa
        FROM table1
        ) AS t1
                ON table2.contract_award_id = t1.xca
                OR table2.solicitation_id = t1.xsa
        ;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X