PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Jointure gauche avec un nom de table dynamique dérivé de la colonne

Dans tous les cas, vous avez besoin de SQL dynamique.

Nom de la table comme paramètre donné

CREATE OR REPLACE FUNCTION foo(_number int)
  RETURNS TABLE (cpa int, nr text, vym text) AS  -- adapt to actual data types!
$func$
BEGIN
   RETURN QUERY EXECUTE format(
      'SELECT t.cpa, substring(t.ku,'[0-9]+'), p.vym 
       FROM   public."table_data_C" t
       LEFT   JOIN %s p USING (cpa)'
     , 'pa' || _number
     );
END
$func$ LANGUAGE plpgsql;

Appel :

SELECT * FROM foo(456887)

Généralement, vous désinfectez les noms de table avec le format ( %I ) pour éviter l'injection SQL. Avec juste un integer comme entrée dynamique qui n'est pas nécessaire. Plus de détails et de liens dans cette réponse connexe :
INSERT avec le nom de la table dynamique dans la fonction de déclenchement

Modèle de données

Il peut y avoir de bonnes raisons pour le modèle de données. Comme le partitionnement/sharding ou les privilèges séparés...
Si vous n'avez pas une si bonne raison, envisagez de consolider plusieurs tables avec un schéma identique en une seule et ajoutez le number comme colonne. Alors vous n'avez pas besoin de SQL dynamique.

Considérez l'héritage . Ensuite, vous pouvez ajouter une condition sur tableoid pour ne récupérer que les lignes d'une table enfant donnée :

SELECT * FROM parent_table
WHERE  tableoid = 'pa456887'::regclass

Soyez cependant conscient des limites de l'héritage. Réponses associées :

Nom de la 2ème table en fonction de la valeur dans la 1ère table

Dériver le nom de la table de jointure des valeurs de la première table complique dynamiquement les choses.

Pour seulement quelques tables

LEFT JOIN chacun sur tableoid . Il n'y a qu'une seule correspondance par ligne, utilisez donc COALESCE .

SELECT t.*, t.tbl, COALESCE(p1.vym, p2.vym, p3.vym) AS vym
FROM  (
   SELECT cpa, ('pa' || substring(ku,'[0-9]+'))::regclass AS tbl
   FROM   public."table_data_C"
   -- WHERE <some condition>
   ) t
LEFT   JOIN pa456887 p1 ON p1.cpa = t.cpa AND p1.tableoid = t.tbl
LEFT   JOIN pa456888 p2 ON p2.cpa = t.cpa AND p2.tableoid = t.tbl
LEFT   JOIN pa456889 p3 ON p3.cpa = t.cpa AND p3.tableoid = t.tbl

Pour de nombreux tableaux

Combinez une boucle avec des requêtes dynamiques :

CREATE OR REPLACE FUNCTION foo(_number int)
  RETURNS TABLE (cpa int, nr text, vym text) AS
$func$
DECLARE
   _nr text;
BEGIN
FOR _nr IN
   SELECT DISTINCT substring(ku,'[0-9]+')
   FROM   public."table_data_C"
LOOP
   RETURN QUERY EXECUTE format(
      'SELECT t.cpa, _nr, p.vym 
       FROM   public."table_data_C" t
       LEFT   JOIN %I p USING (cpa)
       WHERE  t.ku LIKE (_nr || '%')'
     , 'pa' || _nr
     );
END LOOP;

END
$func$ LANGUAGE plpgsql;