Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes PostgreSQL Discussion :

Function utilisation Perform


Sujet :

Requêtes PostgreSQL

  1. #1
    Modérateur

    Function utilisation Perform
    Bonjour,
    J'ai créé la fonction suivante :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    CREATE FUNCTION brain.update_hash_people ()
    	RETURNS bool
    	LANGUAGE plpgsql
    	VOLATILE 
    	CALLED ON NULL INPUT
    	SECURITY INVOKER
    	COST 1
    	AS $$
    DECLARE
    v_id_people int;
    v_hash varchar;
    BEGIN
        -- génère les hash
        FOR v_id_people,v_hash
        IN select id_people,hash from brain.update_hash
        LOOP
            select id_people from brain.people where id_people = v_id_people and hash = v_hash;
            if not found THEN
            update brain.people set hash = v_hash, modification = false;
            end if;
        END LOOP;
    return true;
    END;
    $$;



    du coup j'ai l'erreur suivante :


    SQL Error [42601]: ERROR: query has no destination for result data
    Indice*: If you want to discard the results of a SELECT, use PERFORM instead.
    Où*: PL/pgSQL function update_hash_people() line 10 at SQL statement
    Je modifie donc comme ceci

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    CREATE FUNCTION brain.update_hash_people ()
    	RETURNS bool
    	LANGUAGE plpgsql
    	VOLATILE 
    	CALLED ON NULL INPUT
    	SECURITY INVOKER
    	COST 1
    	AS $$
    DECLARE
    v_id_people int;
    v_hash varchar;
    BEGIN
        -- génère les hash
        FOR v_id_people,v_hash
        IN select id_people,hash from brain.update_hash
        LOOP
            perform id_people from brain.people where id_people = v_id_people and hash = v_hash;
            if not found THEN
            update brain.people set hash = v_hash, modification = false;
            end if;
        END LOOP;
    return true;
    END;
    $$;



    Et là cela tourne en boucle, j’arrête après plusieurs minutes.
    Pouvez-vous m'orienter vers une solution ?

    Merci

  2. #2
    Modérateur

    Pour perform je ne sais pas, mais j'ai quelques remarques sur la fonction.

    Côté non réponse, je suppose que ça vient du manque de where id_people = v_id_people dans l'update (ligne #20-21) - du coup toute la table est mise à jour à chaque ligne du select, c'est long et ça génère beaucoup de contention.

    Ensuite la logique me paraît erronée, j'aurai écrit une simple commande comme ceci :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     merge into brain.people as tgt
     using brain.update_hash as src
        on tgt.id_people    = src.id_people
      when matched then update
       set tgt.hash         = src.hash
         , tgt.modification = false
     where tgt.hash        <> src.hash
        or tgt.hash        is null;

    Syntaxe à vérifier, je ne suis pas sûr du niveau d'implémentation de la commande MERGE chez PostgreSQL.

  3. #3
    Modérateur

    Merge n'existe pas chez PostgreSQL, en tout cas pas l'implémentation standard de SQL, il faut utiliser upsert.
    Par contre oui, j'ai vu ce matin que j'avais oublié le where.
    En fait, le souci, venais...de je ne sais où, il à juste fallut réorganiser le façon de faire, je ne pense pas que cela soit la meilleur solution, mais je fais ceci qui fonctionne :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    CREATE FUNCTION brain.update_hash_people ()
    	RETURNS bool
    	LANGUAGE plpgsql
    	VOLATILE 
    	CALLED ON NULL INPUT
    	SECURITY INVOKER
    	COST 1
    	AS $$
    DECLARE
    v_id_people int;
    v_hash varchar;
    v_compteur integer;
    BEGIN
        -- génère les hash
        FOR v_id_people,v_hash
        IN select id_people,hash from brain.update_hash
        LOOP
            select count(id_people) into v_compteur from brain.people where id_people = v_id_people and hash = v_hash;
            if v_compteur = 0 THEN
            update brain.people set hash = v_hash, modification = false where id_people = v_id_people;
            end if;
        END LOOP;
    return true;
    END;
    $$;


    En gros j'ajoute une variable (v_compteur) dans le process et c'est lui qui va me servir de discriminant.
    Je pense que PostgreSQL ne sait pas me dire si je retourne quelque chose ou pas...je m'y prend surement mal.

    Maintenant , je vais me pencher sur ta solution.

    merci.

  4. #4
    Modérateur

    Peut-être comme ceci :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    update brain.people      as tgt
       set tgt.hash         = src.hash
         , tgt.modification = false
      from brain.update_hash as src
     where tgt.id_people    = src.id_people
       and (tgt.hash       <> src.hash
        or  tgt.hash       is null);

###raw>template_hook.ano_emploi###