2
votes

Évitez les doublons dans INSERT INTO dans la même table

J'ai un programme en JAVA qui crée une table dans une base de données, puis j'insère des lignes dans cette table. Le tableau est créé comme ci-dessous:

        String sql = "INSERT INTO weather VALUES(?,?,?,?,?,?,?);";

Lorsque j'ajoute des lignes, je ne veux pas avoir de doublons pour le champ nommé "ville". Donc, par exemple, si j'ai déjà Londres avec ses données, je ne veux pas l'ajouter à nouveau, même si toutes ses données peuvent avoir changé. Je veux l'avoir une seule fois dans ma table.

J'ai cette requête à insérer:

        String sql = "CREATE TABLE IF NOT EXISTS weather (\n"
            + " city string,\n"
            + " temp real,\n"
            + " feels_like real,\n"
            + " temp_min real,\n"
            + " temp_max real,\n"
            + " pressure integer,\n"
            + " humidity integer\n"
            + ");";

et je veux le modifier pour ne pas insérer de doublons de ville. Quelqu'un peut-il m'aider s'il-vous-plaît? Merci!


1 commentaires

Pourquoi ne pas définir la ville comme UNIQUE ? Facilite beaucoup de choses


3 Réponses :


-1
votes

Vous pouvez maintenant utiliser on conflict . Cela nécessite que vous ayez un index / contrainte unique sur la city mais il est déjà défini comme clé primaire. Vérifier.

insert or ignore into weather ( . . . )
    values ( . . . );

SQLite permet également ce raccourci:

insert into weather ( . . . )
    values ( . . . )
    on conflict (city) ignore;


6 commentaires

J'ai essayé les deux, mais aucun d'eux ne semble fonctionner. Ils continuent d'ajouter la ligne avec la même ville.


Quelle version de SQLite utilisez-vous? Cela est pris en charge depuis la version 3.24 de SQLite. Le vote négatif est plutôt impoli, étant donné que cette réponse a des références à la documentation SQLite illustrant que le code fonctionne.


@GordenLinoff C'est PSQLese, et ne fonctionnerait pas du tout à moins d'avoir un index unique ou une définition PK appropriée. Cela ne fonctionne pas non plus avec mssql, mysql et de nombreux autres moteurs de base de données.


... d'oh, les balises de cette question (maintenant?) incluent sqlite. Nevermind, continuez :)


@GordonLinoff c'est la version 3.32.


@rzwitserloot. . . Le code de la question spécifie que la city est une clé primaire et cela est couvert dans la réponse.



0
votes

Il n'y a aucun moyen de faire cela en "SQL standard effectivement" *.

Mais, chaque moteur de base de données individuel a généralement un moyen d'atteindre cet objectif.

Le concept s'appelle fusion ou upserting - ce sont des termes que vous pouvez rechercher sur le Web. Il suffit de rechercher «comment postgres upsert» par exemple. Cela s'appelle upsert parce que l'application la plus générale est la suivante: Si un sous-ensemble des valeurs que j'insère n'existe pas encore dans la base de données, INSÉRER une nouvelle ligne avec ces données. Sinon, recherchez la ligne avec les mêmes valeurs pour ce sous-ensemble, puis mettez à jour toutes les autres valeurs avec elle. Par exemple: «Trouvez l'élève avec l'ID 12345, puis changez le nom en« Joe Bloggs ». S'il n'y a pas de ligne avec cela, créez-le».

faites TOUTES les valeurs «la clé» et vous avez réduit votre «insérer, ignorer si elle est déjà là» à un UPSERT standard.

Dans psql, vous pouvez faire ON CONFLICT. la recherche de 'mysql upsert' vous amène à des articles de blog qui vous donnent des tactiques variables en fonction de vos besoins exacts, en utilisant INSERT IGNORE (je déconseille cela, cela ignore toutes les erreurs, vs n'ignore que l'erreur `` déjà ici '' ), ON DUPLICATE KEY UPDATE (meilleure idée, ceci), ou en utilisant REPLACE.

Des articles de blog similaires seront trouvés pour tout moteur de base de données que vous utilisez ici.

*) Défini non pas comme «selon une version du standard SQL», mais défini comme: «fonctionne dans la majorité des moteurs de base de données existants».


0 commentaires

1
votes

Si la version de SQLite que vous utilisez est 3.24.0+ et il y a une contrainte unique pour la colonne city , vous pouvez utiliser upsert qui vous donne la possibilité de faire NOTHING ou UPDATE la table si une violation de contrainte unique se produit.

Dans ce cas:

String sql = 
    "INSERT INTO weather SELECT ?,?,?,?,?,?,? " +
    "WHERE NOT EXISTS (SELECT 1 FROM weather WHERE city = ?);

si vous essayez d'insérer une ligne avec une city existante, l'instruction échouera sans erreur.

Mais si la nouvelle ligne contient des données à jour pour les autres colonnes et que vous souhaitez que la ligne soit mise à jour, vous pouvez le faire:

String sql = 
    "INSERT INTO weather VALUES(?,?,?,?,?,?,?) " +
    "ON CONFLICT(city) DO UPDATE SET "
    "temp = excluded.temp, " + 
    "feels_like = excluded.feels_like, " + 
    "temp_min = excluded.temp_min, " + 
    "temp_max = excluded.temp_max, " + 
    "pressure = excluded.pressure, " + 
    "humidity = excluded.humidity";

et les 6 autres colonnes seront écrasées par les nouvelles valeurs que vous avez fournies.

S'il n'y a pas de contrainte unique définie pour la city et que vous ne voulez pas ou ne pouvez pas en définir une, vous pouvez éviter d'insérer la même ville deux fois avec NOT EXISTS comme ceci:

String sql = 
    "INSERT INTO weather VALUES(?,?,?,?,?,?,?) " +
    "ON CONFLICT DO NOTHING";

Dans ce cas, vous devrez à nouveau passer dans votre code Java comme 8ème paramètre supplémentaire la valeur de la city .


6 commentaires

J'ai essayé toutes vos options, mais elles ne fonctionnent pas. Ils continuent d'ajouter la même ville.


@WillWost J'ai remarqué que vous avez modifié votre question et supprimé PRIMARY KEY de la ville. Pourquoi? Les 2 premières requêtes devraient fonctionner si la ville est la clé primaire. Le dernier fonctionne dans tous les cas. Publiez le code Java que vous exécutez.


Je l'ai édité parce que je ne veux pas que la ville soit une clé primaire. C'était juste un test que j'avais fait, mais j'avais oublié de le supprimer. J'ai réessayé maintenant en créant une nouvelle base de données et la première requête que vous m'avez proposée fonctionne. Est-ce normal? J'ai ajouté deux contraintes pour la ville: NOT NULL et UNIQUE.


@WillWost Bien sûr, c'est normal. C'est ainsi que cela est censé fonctionner. S'il y a une violation de contrainte UNIQUE, la clause ON CONFLICT DO NOTHING fera que l'instruction ne fasse rien.


J'ai aussi une autre question s'il vous plaît. Dans la deuxième question, qu'est-ce qui est exclu pour vous? Je ne comprends pas. Merci beaucoup !


@WillWost excluded est un mot clé qui qualifie toutes les valeurs que vous avez essayé d'insérer mais qui ont échoué. Alors excluded.feels_like est la valeur que vous avez passé pour feels_like dans l'instruction INSERT.