2013-07-04 4 views
1

j'ai mis en place une fonction qui vérifie si une valeur apparaît dans une ligne spécifique d'une table spécifique:erreur de fonction postgresql: nom de la colonne n'existe pas

CREATE FUNCTION check_if_if_exist(id INTEGER, table_name character(50), table_column character(20)) RETURNS BOOLEAN AS $$ 

DECLARE res BOOLEAN; 

BEGIN 
    SELECT table_column INTO res 
    FROM table_name 
    WHERE table_column = id; 

    RETURN res; 
END; 

$$ LANGUAGE plpgsql 

j'ai créer et remplir une table de test simple pour essayer cette fonction:

CREATE TABLE tab(f INTEGER); 

et j'appelle la fonction comme

SELECT check_if_exist(10, tab, f); 

mais je produit dans cette erreur:

ERROR: column "prova" does not exist 
LINE 1: SELECT check_if_exist(10, tab, f); 
          ^


********** Error ********** 

ERROR: column "tab" does not exist 
SQL state: 42703 
Character: 27 

pourquoi?

+0

Si vous essayez de le faire dans le cadre d'une opération de type "insérer si non existant" ou "mettre à jour, insérer si non existant", veuillez vous arrêter maintenant et lire à propos de upsert sur PostgreSQL. Si ce n'est pas ce que vous faites, peut-être éditer et expliquer quel est votre véritable objectif, car il est difficile d'imaginer une fonction comme celle-ci ayant une utilité là où il n'y a pas de meilleure façon de le faire. –

Répondre

2

Votre code n'a aucune chance de travailler - lorsqu'ils traitent avec des tables différentes plpgsql vous avez besoin d'utiliser des requêtes dynamiques, donc EXECUTE est nécessaire - http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
Mais avant tout - il n'y a rien de mal à utiliser PostgreSQL EXISTS-http://www.postgresql.org/docs/current/static/functions-subquery.html#AEN15284 à la place d'inventer la vôtre - la performance de votre solution sera bien pire que celle des piles incluses ...
J'espère que cela vous sera utile. Bonne chance.

2

En plus de la réponse Elmo, vous devez faire attention aux types. Vous avez:

ERROR: column "tab" does not exist 

parce que l'analyseur SQL ne sais pas comment faire face à tab qui est sans citation. Votre requête doit être comme:

SELECT check_if_exist(10, 'tab', 'f'); 

Comme Elmo a répondu que vous utilisez requête dynamique, même si vous citez tab vous eu erreur:

ERROR: relation "table_name" does not exist 

, vous pouvez utiliser EXECUTE, par exemple:

CREATE OR REPLACE FUNCTION check_if_exist(id INTEGER, table_name varchar, table_column varchar) RETURNS BOOLEAN AS $$ 
    DECLARE 
     sql varchar; 
     cnt int; 
    BEGIN 
     sql := 'SELECT count(*) FROM ' || quote_ident(table_name) || ' WHERE ' || quote_ident(table_column) || '=$1'; 
     RAISE NOTICE 'sql %', sql; 
     EXECUTE sql USING id INTO cnt; 
     RETURN cnt > 0; 
    END; 
$$ LANGUAGE plpgsql 

Vous pouvez également utiliser VARCHAR au lieu de character(N) dans les arguments de fonction et utiliser CREATE OR REPLACE FUNCTION ... au lieu de seulement CREATE FUNCTION ... qui est très pratique au débogage.

+4

Veuillez ne jamais afficher 'EXECUTE' avec une concaténation de chaîne directe. Cela fait de la fonction un vecteur pour l'injection SQL. Ce qui précède doit être écrit 'format EXECUTE ('SELECT count (*) FROM% I WHERE% I = $ 1', nom_table, table_column) USING id INTO cnt;' ou, pour les versions plus anciennes de PostgreSQL sans 'format', devrait envelopper la table et les noms de colonnes dans les appels 'quote_ident'. –

+0

+1 pour la réponse, cependant @CraigRinger a raison avec ses préoccupations, donc +1 pour lui aussi. C'est bien de montrer à OP comment faire des requêtes dynamiques et empêcher l'injection SQL, mais je dis toujours que l'écriture de cette fonction précise réinvente la roue. – ElmoVanKielmo

+0

Merci, je viens d'éditer la réponse. Je ne vois pas cette fonction très utile quand on peut utiliser 'select exists (sélectionnez * from my_table où my_column = my_value)'. –

Questions connexes