Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
#76 Général » Coder en PL/pgSQL sans passer par la création d'une fonction » 20/10/2011 19:47:40
- guk92
- Réponses : 15
Bonsoir,
Je souhaiterais savoir s'il existe un moyen de coder en PL/pgSQL sans passer par la création de fonction.
Je souhaiterais en faite effectuer des tests, m'entrainer à pratiquer le langage, mais à chaque fois je dois passer par la création d'une fonction de test.
Existe-t-il un moyen de faire du PL/pgSQL sans créer de fonction ?
Je vous remercie ![]()
#77 Re : Général » Plusieurs questions techniques » 11/10/2011 13:59:25
Tout d'abord je tiens à vous remercier pour vos réponses et je vais commencer par répondre à ta question Gleu.
Il est en effet possible de faire des CREATE TABLE dans une transaction sous SQL Server, voici la preuve en image d’une procédure contenant une transaction (contenant elle-même une création de table) :
PS: j'ai remarqué que j'ai inséré un entier dans une colonne de type char, mais ça fonctionne
(
).
Par rapport à ta réponse n°4 :
Une fonction est en elle-même une transaction
Si c'est vrai pour PostgreSQL c'est génial, ainsi pas de problème entre différents utilisateurs qui lancent en même temps la fonction (ou procédure).
Par contre je ne sais pas s'il est considéré de même pour une procédure sous SQL Server, car il m'a déjà semblé exécuter une procédure (sans transactions et contenant plusieurs requêtes d'insertion) sur deux clients en même temps, et les données que j'ai inséré dans une même table étaient mélangés dans le temps (un coup un bloc de données insérées provenant du client 1, un coup un bloc de données insérées provenant du client 2 et ainsi de suite).
La preuve en image :
(Les données des utilisateurs 1 et 2 sont mélangés => on n'a pas une suite de 1, puis une suite de 2).
Bien sur ces tests étaient sous SQL Server 2005 sans mises à jour, je ne sais pas si cela a changé depuis.
Mais sinon il est aussi possible de créer des tables dans des transactions sous PostgreSQL :
BEGIN;
CREATE TABLE tableTest1(colonne1 integer);
INSERT INTO tableTest1(colonne1) VALUES(134);
COMMIT;
SELECT * FROM tableTest1;Par contre, pour les INDEX sous SQL Server je ne sais pas du tout (pas encore pratiqué).
Rjuju,
Il est aussi possible de faire des SAVEPOINT sous SQL Server, sauf que le mot-clé est SAVE, il faut lui ajouter impérativement TRANSACTION et un nom de point de sauvegarde :
-- PostgreSQL :
SAVEPOINT pointSauvegarde ;
-- SQL Server :
SAVE TRANSACTION pointSauvegarde ;Autrement, d'après un exemple officiel SQL Server, il est possible de créer des transactions dans des transactions :
BEGIN TRAN T1;
UPDATE table1 ...;
BEGIN TRAN M2 WITH MARK;
UPDATE table2 ...;
SELECT * from table1;
COMMIT TRAN M2;
UPDATE table3 ...;
COMMIT TRAN T1;Gleu,
Pour ma question n°2, me conseillez-vous de ne pas utiliser de RETURNS type lorsque j'utilise un paramètre en mode OUT ?
Car à vrai dire, je ne vois pas l'utilité de mettre un RETURNS type si cela fonctionne sans ![]()
Merci
#78 Général » Plusieurs questions techniques » 10/10/2011 22:16:13
- guk92
- Réponses : 9
Bonsoir,
J'ai de nouveau plusieurs questions en tête, je les ai donc de mis de coté pour vous les poser ce soir si cela ne vous embête pas.
Les questions sont plutôt longues mais les réponses peuvent se résumer à un OUI ou NON (avec peut-être une phrase d'explication si le coeur y est
).
Mes premières questions portent sur les procédures, fonctions et requêtes type "INSERT / UPDATE / DELETE" :
1. Une procédure ou fonction sous PostgreSQL commence avec la syntaxe "CREATE FUNCTION", donc pour distinguer une procédure d'une fonction, une procédure est censée retourner un void (RETURNS void) et une fonction tout les autres types (RETURNS integer etc...), est-ce bien cela ?
2. J'ai remarqué que les FUNCTION contenant au moins un argument en mode OUT ne peuvent pas avoir de RETURNS void, mais peuvent contenir un RETURNS integer ! ... ou rien (ce que je trouve plus normal).
Normalement, un FUNCTION contenant un paramètre OUT doit être considéré comme une procédure et non une fonction, car d'après ce que j'ai vu sous SQL Server, seules les procédures peuvent contenir des arguments en mode OUT (appelé OUTPUT sous SQL Server) mais pas les fonctions.
Donc pourquoi une FUNCTION avec des arguments en mode OUT peut contenir un RETURNS integer ?
Pourquoi ne peut-t-il pas contenir de RETURN value dans le cas où l’on fait RETURNS integer ?
Est-ce un bug ?
Exemple de test :
CREATE FUNCTION test(OUT var1 integer, var2 integer, var3 integer)
/* Je suis obligé d'avoir un RETURNS type différent de void lorsque j'ai des arguments en mode OUT,
mais je peux enlever le RETURNS value et cela fonctionne */
RETURNS integer -- Ou rien
AS $$
BEGIN
INSERT INTO t1(date, vala, valb, valc) VALUES(NOW(), var1, var2, var3);
RETURN 1; -- Ceci génère une erreur lorsque j'ai un paramètre en mode OUT et RETURNS integer.
END;
$$ LANGUAGE plpgsql;3. J'ai remarqué que les FUNCTION PostgreSQL retournant une valeur (donc une fonction et non une procédure) peuvent contenir des requêtes de type INSERT / UPDATE / DELETE, est-ce que c'est normal ? Pourquoi ?
Pour comparaison, sous SQL Server, seules les procédures (CREATE PROCEDURE) peuvent contenir ce type de requête (INSERT INTO / UPDATE / DELETE) et non les fonctions (CREATE FUNCTION).
Les trois questions qui vont suivre, portent sur les transactions :
4. J'ai créé une transaction sous Query de PostgreSQL :
BEGIN;
INSERT INTO t1(date, vala, valb, valc) VALUES(NOW(), 1, 1, 1);
UPDATE t1 SET date=NOW() WHERE id = 1;
COMMIT;Ce bout de code fonctionne parfaitement, pourtant lorsque j'essaye de l'intégrer dans une procédure, cela ne fonctionne pas et j'ai une erreur SQL 42601 qui apparaît.
Ne peut-t-on pas faire de transaction dans des procédures sous PostgreSQL ? J'ai créé une procédure contenant une transaction sous SQL Server et cela fonctionne.
5. J'ai essayé de créer une transaction contenant une autre transaction (cela s'appelle nested transaction d'après ce que j'ai lu sur internet) en reprenant l'exemple précédent :
BEGIN;
INSERT INTO t1(date, vala, valb, valc) VALUES(NOW(), 1, 1, 1);
BEGIN;
UPDATE t1 SET date=NOW() WHERE id = 1;
COMMIT;
COMMIT;J'ai ce message qui apparaît :
ATTENTION: une transaction est déjà en cours
ATTENTION: aucune transaction en coursLa requête a été exécutée avec succès en 15 ms, mais ne renvoie aucun résultat.
Pourquoi un message d'avertissement apparaît ? N'a-t-on pas le droit de faire cela en temps normal ?
6. J'ai vu des exemples sur internet avec un bloc de transaction contenant une seule requête seulement.
Est-ce qu'il peut être utile d'avoir un bloc de transaction ne contenant qu'une seule requête seulement ?
Si oui pourquoi ?
Est-ce que c'est parce ce qu'une requête peut prendre du temps à s'exécuter et qu'entre temps on ne veut pas qu'il y ait un changement pouvant être provoqué par un autre utilisateur ?
Ma dernière question est plus lié à la norme SQL :
7. Est-ce que les jointures avec la clause USING font parti de la norme SQL ?
-- Forme 1, tel qu’on la connaît
SELECT champs
FROM table1
JOIN table2
ON table1.id = table2.id
-- Équivalent forme 2 avec USING
SELECT champs
FROM table1
JOIN table2
USING(id)Je vous remercie pour vos réponses ![]()
#79 Re : Général » Deux erreurs détectées dans la documentation » 10/10/2011 20:29:11
Bonsoir SQLpro,
Apprendre des choses sur PostgreSQL et la norme SQL pour une personne comme moi qui vient de SQL Server est une expérience très enrichissante.
D'ailleurs, d'après ce que j'ai vu, vous êtes vous même consultant SQL Server, donc dire que les personnes qui se trouvent sur ce forum ne s'intéresse qu'à PostgreSQL serait faux.
#80 Re : Général » Jointures avec les requêtes UPDATE sous PostgreSQL » 09/10/2011 23:48:15
Je vous remercie pour vos réponse ![]()
En effet, après avoir vu la syntaxe sur la possibilité de faire une jointure avec un UPDATE sur PostgreSQL de Rjuju j'en suis arrivé au même résultat que Dverite.
@Rjuju
La syntaxe suivante fonctionne :
UPDATE table as ALIAS ....
SET colonne = ...
FROM table
-- et JOIN si besoin... mais je pense qu'elle est inutile car l'ALIAS ne sert à rien ![]()
Ceci provoque une erreur :
UPDATE table as ALIAS ....
SET [b]ALIAS.colonne[/b] = ...
FROM table
-- et JOIN si besoin@Dverite
Pour ce qui est de la version Standard, il est plus simple à comprendre certes, mais il nécessite de créer autant de requête que de champ à mettre à jour, c'est très gênant quand on cherche à optimiser (c'est le but recherché de cette technique en faite).
Cette "technique" ne fait pas parti de la norme SQL à ce que j'ai compris, par contre je comprend le fait que PostgreSQL l'ait ajouté, car il peut être très utile ( et fera peut-être parti du Standard SQL un jour
).
Pour finir j'ai trouvé un compromis entre SQL Server et PostgreSQL, il est en effet possible d'utiliser la syntaxe suivante pour les deux SGBD (copier/coller de Dverite) :
UPDATE Table1
SET colonneCount=s.monCount, colonneMax=s.monMax, colonneMin =s.monCount
FROM (SELECT COUNT(*) AS monCount, MAX(val) AS monMax, MIN(val) AS monMin FROM Table2) s
WHERE Table1.id = 1;Pour ce qui est de SQL Server, il est possible de faire "UPDATE alias" (ce que j'avais l'habitude de faire) ou le nom de la table "UPDATE table" (ce que fait uniquement PostgreSQL, et c'est pas plus mal
).
#81 Général » Jointures avec les requêtes UPDATE sous PostgreSQL » 09/10/2011 19:33:45
- guk92
- Réponses : 6
Bonsoir,
Venant de SQL Server, je sais qu'il est possible de faire des jointures sur des requêtes UPDATE, mais sous PostgreSQL mes tests n'ont rien donnés.
Pour vous montrer un exemple, une requête ayant cette syntaxe fonctionne sous SQL Server :
UPDATE monAliasTable1
SET
monAliasTable1.colonneCount = monAliasTable2.monCount,
monAliasTable1.colonneMax = monAliasTable2.monMax,
monAliasTable1.colonneMin = monAliasTable2.monMin
FROM test.dbo.Table1 AS monAliasTable1
/* JOINTURES POSSIBLES */
INNER JOIN (SELECT COUNT(*) AS monCount, MAX(val) AS monMax, MIN(val) AS monMin FROM test.dbo.Table2) AS monAliasTable2
ON monAliasTable1.id = 1;Ceci n'est qu'un bref exemple, mais il est ainsi possible de faire des requêtes UPDATE avec des jointures dans SQL Server, ce qui peut-être très efficace lorsqu'on souhaite regrouper un maximum de résultat à partir d'une seule requête.
J'ai essayé de faire la même chose sous PostgreSQL mais cela n'a rien donnée, pourtant dans la documentation il est possible d'ajouter FROM :
UPDATE [ ONLY ] table SET colonne = { expression | DEFAULT } [, ...]
[ FROM liste_from ]
[ WHERE condition ]J'ai donc plusieurs questions qui me trottent en tête :
1. Est-ce qu'il est possible de faire des requêtes UPDATE pouvant contenir des jointures comme sous SQL Server ? Si oui puis-je avoir un exemple ? ![]()
2. Est-ce que cette technique ( que je trouve personnellement très efficace
) fait parti de la norme SQL ? ![]()
Autrement sous SQL Server, il est possible d'avoir cette syntaxe :
DELETE t1 FROM test.dbo.Table1 AS t1 ...Cette forme ne fonctionne-t-elle vraiment pas sous PostgreSQL ou sinon c'est moi qui m'y prend mal ? ![]()
Si cela ne fonctionne pas sous PostgreSQL je suppose que cette syntaxe ne doit pas faire parti de la norme ? (enfin je pense).
Merci et bonne soirée. ![]()
#82 Re : Général » Deux erreurs détectées dans la documentation » 06/10/2011 16:48:01
Les messages s'affichent bien dans l'onglet "Messages".
Je vous remercie pour vos réponses.
#83 Re : Général » Deux erreurs détectées dans la documentation » 06/10/2011 15:58:04
Veuillez m'excuser pour cette erreur de copier/coller de RAISE NOTICE, le problème persiste toujours :
DROP FUNCTION p_boucleFor();
CREATE OR REPLACE FUNCTION p_boucleFor()
RETURNS void AS $$
BEGIN
FOR i IN REVERSE 3..1 LOOP
RAISE NOTICE 'valeur de i : %', i;
END LOOP; -- Fin de la boucle FOR
END;
$$ LANGUAGE plpgsql;
SELECT p_boucleFor();Rien ne s'affiche.
Voici le problème en image :
Merci
#84 Re : Général » Deux erreurs détectées dans la documentation » 06/10/2011 14:05:31
Je ne connaissais pas le SQL-PSM, j'ai lu un très court article en anglais sur Wikipédia.
Je ne sais pas contre pas lequel je vais utiliser entre en ELSIF ou ELSEIF (je suis pointilleux).
Je confirme pour la 2. après test. Par contre ça prouve que les code PL/pgSQL et PL/SQL ne sont pas portables pour les boucles FOR.
Au faite j'ai essayé de faire un affichage grâce à la commande NOTICE RAISE mais je n'ai pas réussis à afficher quoi que ce soit :
CREATE OR REPLACE FUNCTION p_boucleFor()
RETURNS void AS $$
BEGIN
FOR i IN REVERSE 3..1 LOOP
NOTICE RAISE 'valeur de i : %', i;
END LOOP; -- Fin de la boucle FOR
END;
$$ LANGUAGE plpgsql;
SELECT p_boucleFor();Rien ne s'affiche sous Query, pourquoi ?
Pour les fonctions, je trouve la syntaxe un poil compliqué, car il n'est pas possible de déclarer des variables dans le second BEGIN de ton exemple, du coup je préfère déclarer toutes les variables une seule fois de cette manière :
CREATE [OR REPLACE] FUNCTION nomProcedure()
RETURNS type AS $$
/* Déclarer toutes les variables ICI */
BEGIN -- Début de la procédure ou fonction
/* Traitement */
END; -- Fin de la procédure ou fonction
$$ LANGUAGE plpgsql;C'est dommage car il est possible de déclarer des variables où l'on veut en T-SQL sous SQL Server.
Merci.
#85 Général » Deux erreurs détectées dans la documentation » 06/10/2011 12:29:32
- guk92
- Réponses : 10
Bonjour,
J'ai remarqué 2 "erreurs" dans la documentation, du moins j'ai cette impression.
Si ce n'est pas le cas, je vous prie de me rectifier.
Tout d'abord la source des informations viennent de la documentation officielle PostgreSQL :
http://www.postgresql.org/docs/9.1/stat … tures.html
Dans les conditions IF/ ELSEIF / ELSE, on peut y lire :
The key word ELSIF can also be spelled ELSEIF. (pour PostgreSQL 9.1)
Dans une version plus ancienne de la documentation, on peut aussi y lire :
ELSEIF is an alias for ELSIF. (pour PostgreSQL 8.2)
Or d'après le Standard SQL, j'ai vu sur developpez.com que le mot-clé ELSEIF fait partit de la norme, tandis que le mot-clé ELSIF n'y figure pas.
C'est donc ELSIF qui devrait être un ALIAS de ELSEIF et pas le contraire.
En tout cas en PL/SQL (Oracle), c'est bien le mot-clé ELSIF qui est employé (mais fait-il parti de la norme ?).
Avec la boucle FOR (c'est la même chose avec toutes les versions PostgreSQL des documentations utilisateur):
FOR i IN 1..10 LOOP
-- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
FOR i IN REVERSE 10..1 LOOP
-- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop
END LOOP;
Il y a une incohérence dans la seconde boucle par rapport à un exemple PL/SQL :
The FOR Loop can also loop in reverse. For example:
FOR Lcntr IN REVERSE 1..15
LOOP
-- Statements
END LOOP;
This example will loop 15 times. The counter will start at 15 and end at 1. (loops backwards)
Donc l'exemple :
FOR i IN REVERSE 10..1 LOOP
-- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop
END LOOP;
Devrait plutôt s'écrire :
FOR i IN REVERSE 1..10 LOOP
-- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop
END LOOP;
Autrement je souhaiterais savoir s'il est possible de déclarer des variables dans une FUNCTION entre le BEGIN et le END, car j'ai essayé et ça n'a pas marché, il m'a semblé avoir vu qu'il était possible de déclarer une variable entre le BEGIN et END dans une FUNCTION dans la documentation.
Est-t-il possible de déclarer une variable autre part qu'entre le FUNCTION() et BEGIN ?
Merci et bonne continuation.