Élégante façon de gérer PostgreSQL exceptions?
Dans PostgreSQL, je voudrais créer un coffre-mécanisme d'emballage qui retourne un résultat vide si une exception se produit. Considérez les points suivants:
SELECT * FROM myschema.mytable;
Je pouvais faire le coffre d'habillage dans l'application client:
try {
result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
result = []
}
Mais ai-je pu faire une telle chose en SQL directement? Je voudrais faire le code suivant travail, mais il semble comme il se doit par le mettre en DO $$ ... $$
bloc et là je suis perdu.
BEGIN
SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
SELECT unnest(ARRAY[]::TEXT[])
END
DO
ne retourne rien. Vous devez utiliser une procédure stockée (avec la langue plpgsql
-- pour la gestion des exceptions). - pas de lignes retournées n'est pas égal à un ligne unique retourné, avec un tableau vide en elle (c'est à dire en js, cela signifie [] != [{col1:[]}]
).Désolé pour ça, j'ai ajouté
unnest
à mon exemple pour produire le comportement souhaité (vous ne savez pas comment faire cela de manière plus élégante). De toute façon, dois-je déclarer la procédure à chaque fois que je suis à l'exécution d'une requête avec la gestion des exceptions? Il n'y a pas d'autre option?Donc, vous voulez défendre contre tout et alll exceptions ou êtes-vous juste peur que la table peut ne pas exister? Et que voulez-vous revenir? Une valeur unique de la seule colonne
value
? Ou un ensemble de lignes? Et est-ce pour hard-codée nom de la table ou pour toute une série de noms de table?non, si vous voulez faire gestion des exceptions de plus simple, les requêtes, cette opération est généralement effectuée par le client, et non sur le serveur.
plpgsql
's la gestion des exceptions est principalement stockée "logique". Mais ce type d'exception-vous peur? Peut-être, il existe une alternative.En fait, dans mon cas précis, je suis très inquiète à propos des conditions de course. Je suis en utilisant
SELECT ('myschema','mytable') IN (SELECT table_schema,table_name FROM information_schema.tables);
pour vérifier si la table existe, et si c'est le cas, je suis à la sélection de ses lignes. Mais il arrive souvent que le tableau cesse d'exister avant la deuxième requête est exécutée (c'est à dire, l'idiome "si la table existe, sélectionner son contenu" ne fonctionne pas). C'est pourquoi je voudrais simplement revenir à vide suite si une exception se produit.
OriginalL'auteur Tregoreg | 2015-02-10
Vous devez vous connecter pour publier un commentaire.
La gestion des exceptions dans PL/pgSQL.
Généralement, plpgsql code est toujours enveloppé dans un
BEGIN .. END
bloc. Qui peut être à l'intérieur du corps d'unDO
déclaration ou d'une fonction. Les blocs peuvent être imbriquées à l'intérieur - mais ils ne peuvent pas exister à l'extérieur, ne pas confondre avec la plaine SQL.Chaque
BEGIN
bloc peut éventuellement inclure unEXCEPTION
clause pour la gestion des exceptions, mais les fonctions qui en ont besoin pour intercepter les exceptions sont beaucoup plus coûteux, il est donc préférable d'éviter les exceptions à priori.Plus d'informations:
Le manuel sur la façon d'intercepter les erreurs (gérer les exceptions) en PL/pgSQL.
Exemple: Est de les SÉLECTIONNER ou de les INSÉRER dans une fonction sujettes à des conditions de course?
La recherche de réponses sur DONC
Comment éviter une exception dans l'exemple
Un
déclaration ne peut pas revenir en quoi que ce soit. Créer un fonction qui prend la table et le nom du schéma que les paramètres et renvoie ce que vous voulez:
Appel:
Ou:
En supposant que vous voulez un jeu de lignes avec un seul
text
colonne ou une chaîne vide si la table n'existe pas.Suppose également que l'une colonne
value
existe que si la table existe. Vous pouvez le tester pour que, aussi, mais vous ne demandez pas pour qui.Les deux paramètres sont sensible à la casse
text
valeurs. C'est subtilement différent de la façon dont les identifiants SQL sont manipulés. Si vous n'avez jamais double-quote identifiants, passe en minuscules les noms et vous êtes bien.Le nom de schéma par défaut
'public'
dans mon exemple. S'adapter à vos besoins. Vous pouvez même ignorer le schéma complètement et par défaut à l'actuelsearch_path
.to_regclass()
est nouveau dans Postgres 9.4. Pour les anciennes versions de substitution:C'est en fait plus précis, car il teste exactement ce dont vous avez besoin.
Plus d'options et une explication détaillée:
Toujours défendre contre les injections SQL lorsque l'on travaille avec SQL dynamique! Le casting de
regclass
fait le tour ici. Plus de détails:Ajout d'un bit sur la gestion des exceptions en général.
Je me suis finalement retrouvé avec
BEGIN .. END
à l'intérieur deDO
bloc pour monINSERT
états où les conditions de course peut facilement se produire et je n'ai absolument pas besoin de sélectionner quoi que ce soit. J'ai fait un peu de benchmarking et il semble que la gestion des exceptions dans une telle manière que coûte environ 1 ms, ce qui est pleinement satisfaisante pour moi. @ErwinBrandsetter merci pour vos explications claires et mettant l'accent sur la différence entre la plaine SQL et plpgsql, c'est ce qui me manquait.OriginalL'auteur Erwin Brandstetter
Si vous sélectionnez une seule colonne, puis les FUSIONNER() devrait pouvoir faire l'affaire pour vous
Si vous avez besoin de plus de lignes vous pouvez avoir besoin de créer une fonction avec des types.
OriginalL'auteur Lucas