290 votes

Vérification la plus rapide de l'existence d'une ligne dans PostgreSQL

J'ai un certain nombre de lignes que je dois insérer dans une table, mais ces insertions sont toujours effectuées par lots. Je veux donc vérifier si une seule ligne du lot existe dans la table, car je sais alors qu'elles ont toutes été insérées.

Ce n'est donc pas un contrôle de clé primaire, mais cela ne devrait pas avoir trop d'importance. Je voudrais seulement vérifier une seule ligne, donc count(*) n'est probablement pas bon, alors c'est quelque chose comme exists Je suppose.

Mais comme je suis assez novice en matière de PostgreSQL, je préfère demander aux personnes qui s'y connaissent.

Mon lot contient des lignes avec la structure suivante :

userid | rightid | remaining_count

Donc, si la table contient des lignes avec des données userid cela signifie qu'ils y sont tous présents.

0 votes

Vous voulez voir si la table contient TOUTES les lignes, ou toutes les lignes de votre lot ?

0 votes

Toutes les lignes de mon lot oui. elles ont toutes le même champ, je vais l'éditer un peu.

0 votes

Veuillez clarifier votre question. Vous voulez ajouter un lot d'enregistrements, tout ou rien ? Le comptage a-t-il quelque chose de spécial ? (BTW un mot réservé, peu pratique comme nom de colonne)

566voto

Michael.M Points 868

Utilisez le mot clé EXISTS pour un retour VRAI / FAUX :

select exists(select 1 from contact where id=12)

39 votes

Dans le prolongement, vous pouvez nommer la colonne retournée pour une référence facile. Par exemple, select exists(select 1 from contact where id=12) AS "exists"

4 votes

C'est mieux, parce qu'il retournera toujours une valeur (vrai ou faux) au lieu de parfois None (selon votre langage de programmation) qui pourrait ne pas se développer comme vous l'attendez.

2 votes

J'ai effectué un Seq Scan en utilisant cette méthode. Je fais quelque chose de mal ?

47voto

NPE Points 169956

Pourquoi pas simplement :

select 1 from tbl where userid = 123 limit 1;

donde 123 est l'identifiant du lot que vous êtes sur le point d'insérer.

La requête ci-dessus renverra soit un ensemble vide, soit une seule ligne, selon qu'il existe ou non des enregistrements avec l'identifiant donné.

Si cela s'avère être trop lent, vous pouvez envisager de créer un index sur tbl.userid .

si même une seule ligne du lot existe dans la table, dans ce cas je n'ai pas à n'ai pas besoin d'insérer mes lignes car je suis sûr qu'elles ont toutes été insérées.

Pour que cela reste vrai même si votre programme est interrompu au milieu du lot, je vous recommande de vous assurer que vous gérez correctement les transactions de la base de données (c'est-à-dire que l'ensemble du lot est inséré dans une seule transaction).

13 votes

Il peut parfois être plus facile, d'un point de vue programmatique, de "select count(*) from (select 1 ... limit 1)", car il est garanti que cela renvoie toujours une ligne avec une valeur de count(*) de 0 ou 1.

0 votes

@DavidAldridge count(*) signifie toujours que toutes les lignes doivent être lues, alors que limit 1 s'arrête au premier enregistrement et retourne

6 votes

@Imraan Je pense que vous avez mal interprété la requête. Le site COUNT agit sur un élément imbriqué SELECT qui a au plus 1 ligne (parce que le LIMIT est dans la sous-requête).

11voto

wildplasser Points 17900
INSERT INTO target( userid, rightid, count )
  SELECT userid, rightid, count 
  FROM batch
  WHERE NOT EXISTS (
    SELECT * FROM target t2, batch b2
    WHERE t2.userid = b2.userid
    -- ... other keyfields ...
    )       
    ;

BTW : si vous voulez le tout le lot pour échouer en cas de doublon, alors (étant donné une contrainte de clé primaire)

INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count 
FROM batch
    ;

fera exactement ce que vous voulez : soit elle réussit, soit elle échoue.

0 votes

Cela permettra de vérifier chaque ligne. Il veut faire une seule vérification.

1 votes

Non, il fait une seule vérification. La sous-requête n'est pas corrélée. Elle s'arrête dès qu'une paire correspondante est trouvée.

0 votes

Vous avez raison, je pensais que cela faisait référence à la requête externe. +1 à vous

5voto

Royce Points 228
select true from tablename where condition limit 1;

Je crois que c'est la requête que postgres utilise pour vérifier les clés étrangères.

Dans votre cas, vous pourriez aussi le faire en une seule fois :

insert into yourtable select $userid, $rightid, $count where not (select true from yourtable where userid = $userid limit 1);

4voto

Fabian Barney Points 5707
SELECT 1 FROM user_right where userid = ? LIMIT 1

Si votre jeu de résultats contient une ligne, vous n'avez pas besoin d'insérer. Sinon, insérez vos enregistrements.

0 votes

Si le groupe contient 100 lignes, il me renverra 100 lignes, vous pensez que c'est bon ?

0 votes

Vous pouvez le limiter à 1 rang. Les performances devraient être meilleures. Regardez la réponse éditée de @aix pour cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X