Tester la valeur null en fonction des divers paramètres
J'ai une Postgres fonction:
create function myfunction(integer, text, text, text, text, text, text) RETURNS
table(id int, match text, score int, nr int, nr_extra character varying, info character varying, postcode character varying,
street character varying, place character varying, country character varying, the_geom geometry)
AS $$
BEGIN
return query (select a.id, 'address' as match, 1 as score, a.ad_nr, a.ad_nr_extra,a.ad_info,a.ad_postcode, s.name as street, p.name place , c.name country, a.wkb_geometry as wkb_geometry from "Addresses" a
left join "Streets" s on a.street_id = s.id
left join "Places" p on s.place_id = p.id
left join "Countries" c on p.country_id = c.id
where c.name = $7
and p.name = $6
and s.name = $5
and a.ad_nr = $1
and a.ad_nr_extra = $2
and a.ad_info = $3
and ad_postcode = $4);
END;
$$
LANGUAGE plpgsql;
Cette fonction ne donne pas le bon résultat, lorsque l'une ou plusieurs des variables d'entrée sont NULS parce que ad_postcode = NULL
échouera.
Que puis-je faire pour tester la valeur NULL à l'intérieur de la requête?
- Vous pouvez utiliser les arguments de la fonction des noms au lieu de
$1
..$9
. Quelque chose commemyfunction(v_ad_nr integer, v_ad_nr_extra text, ...
et... a.ad_nr = v_ad_nr ...
. Il rend le code beaucoup plus lisible et plus facile à modifier. - Et de lire quelques articles sur la requête SQL de mise en forme. Actuellement, il est horrible. Ou, au moins, l'utilisation d'une interrogation automatique formatage automatique de la requête.
- Merci pour l'allusion à utiliser les noms d'argument, apprécié.
Vous devez vous connecter pour publier un commentaire.
Je suis en désaccord avec certains des conseils dans d'autres réponses. Cela peut être fait avec plpgsql et je pense que c'est surtout de loin supérieur le montage de requêtes dans une application client. Il est plus rapide et plus propre et de l'application envoie uniquement le strict minimum à travers le fil dans les demandes. Les instructions SQL sont sauvegardés dans la base de données, ce qui rend plus facile à maintenir - à moins que vous souhaitez collecter toute la logique métier de l'application cliente, cela dépend de l'architecture générale.
Conseils généraux
Vous n'avez pas besoin de parenthèses autour de la
SELECT
avecRETURN QUERY
Jamais utilisation
name
etid
que les noms de colonnes. Ils ne sont pas descriptives et lorsque vous vous joignez à un groupe de tables (comme vous deveza lot
dans une base de données relationnelle), vous vous retrouvez avec plusieurs colonnes de tous les noms dename
ouid
. Duh.Veuillez format SQL correctement, au moins quand vous posez des questions publiques. Mais le faire en privé, pour votre propre bien.
Fonctions PL/pgSQL
Appel:
Depuis que j'ai fourni des valeurs par défaut pour tous les paramètres de la fonction, vous pouvez utiliser de position notation, nommé notation ou mixte notation dans l'appel de fonction. Plus dans cette réponse:
Fonctions avec un nombre variable de paramètres d'entrée
Pour plus d'explication sur les bases du SQL dynamique, reportez-vous à cette réponse:
Refactoriser un PL/pgSQL fonction pour renvoyer la sortie de diverses requêtes SELECT
La
concat()
fonction est déterminante pour la construction de la chaîne. Il a été présenté avec Postgres 9.1.La
ELSE
branche d'unCASE
déclaration par défautNULL
lorsqu'il n'est pas présent. Simplifie le code.La
à l'AIDE de
clause deEXECUTE
fait de l'injection SQL impossible et permet d'utiliser des valeurs de paramètre directement, exactement comme les requêtes préparées.NULL
valeurs sont utilisées pour ignorer les paramètres ici. Ils ne sont pas utilisés pour la recherche.Simple de la fonction SQL
Vous pourrait le faire avec une simple fonction SQL et éviter SQL dynamique. Pour certains cas, cela peut être plus rapide. Mais je n'allais pas l'attendre dans ce cas. Re-planification de la requête avec ou sans joint et où les conditions de travail est la meilleure approche. Il vous donnera optimisé les plans de requête. Coûts de la planification pour une simple requête de ce genre est presque négligeable.
Identiques appel.
Efficacement ignorer les paramètres avec
NULL
valeurs:Si vous voulez vraiment utiliser les valeurs NULL en tant que paramètres, utilisez cette construction à la place:
Cela permet aussi index à être utilisé.
Également remplacer toutes les instances de
LEFT JOIN
avecJOIN
.SQL Violon avec simplifiée de démonstration pour toutes les variantes.
Vous pouvez utiliser
Il sera de retour
true
sic.name
et$7
sont égaux, ou les deux, sontnull
.Ou vous pouvez utiliser
Il sera de retour
true
sic.name
et$7
sont égaux ou$7
est null.Si vous pouvez modifier la requête, vous pourriez faire quelque chose comme
Plusieurs choses...
D'abord, comme le note de côté: la sémantique de votre requête, besoin d'un survol. Certaines choses dans votre
where
de clauses appartiennent en fait dans votrejoin
clauses, comme:Quand ils ne le font pas, vous avez très probablement doit être l'aide d'un
inner join
, plutôt que d'unleft join
.Deuxième, il y a un
is not distinct from
de l'opérateur, qui peut parfois être utile en place de=
.a is not distinct from b
est essentiellement équivalent àa = b or a is null and b is null
.Noter, cependant, que
is not distinct from
ne PAS utiliser un indice, alors que=
etis null
réellement faire. Vous pouvez utiliser(field = $i or $i is null)
au lieu de cela, dans votre cas particulier, et il donnera le plan optimal si vous utilisez la dernière version de Postgres:https://gist.github.com/ddebernardy/5884267