2009-02-24 5 views
1

Mon application Web analyse les données d'un fichier téléchargé et l'insère dans une table de base de données. En raison de la nature des données d'entrée (données de transaction bancaire), des données en double peuvent exister d'un téléchargement vers un autre. Pour le moment, j'utilise un code hideusement inefficace pour vérifier l'existence de doublons en chargeant toutes les lignes de la base de données dans la mémoire de la base de données et en les parcourant et en comparant chacune des données téléchargées. Inutile de dire que cela peut devenir très lent à mesure que la taille du jeu de données augmente. Donc, je cherche à remplacer cela par une requête SQL (par rapport à une base de données MySQL) qui vérifie l'existence de données dupliquées, par ex.Instruction MySQL SELECT utilisant Regex pour reconnaître les données existantes

SELECT count(*) FROM transactions WHERE desc = ? AND dated_on = ? AND amount = ? 

Cela fonctionne très bien, mais mon cas réel est un peu plus compliqué. La description d'une transaction dans les données d'entrée peut parfois contenir une ponctuation erronée (par exemple, "BANK 12323 DESCRIPTION" peut souvent être représenté par "BANK.12323.DESCRIPTION") donc notre logique de correspondance existante (en mémoire) effectue un peu de nettoyage sur cette description avant de faire une comparaison.

Bien que cela fonctionne dans la mémoire, ma question est peut ce nettoyage se fait dans une instruction SQL je peux déplacer cette logique correspondant à la base de données, quelque chose comme:

SELECT count(*) FROM transactions WHERE CLEAN_ME(desc) = ? AND dated_on = ? AND amount = ? 

Où CLEAN_ME est un proc qui bandes le champ des données erronées. Il est évident que la solution la plus propre (sans jeu de mots!) Consisterait à stocker les données déjà nettoyées dans la base de données (soit dans la même colonne, soit dans une colonne séparée), mais avant que j'y pense J'essaierais de voir s'il y a une façon plus intelligente de contourner cela.

Merci beaucoup

Répondre

1

can this cleaning be done in a SQL statement

Oui, vous pouvez écrire un stored procedure pour le faire dans la couche de base de données:

mysql> CREATE FUNCTION clean_me (s VARCHAR(255)) 
    -> RETURNS VARCHAR(255) DETERMINISTIC 
    -> RETURN REPLACE(s, '.', ' '); 

mysql> SELECT clean_me('BANK.12323.DESCRIPTION'); 

BANK 12323 DESCRIPTION 

Cela se produira très mal sur une grande table bien.

Obviously the cleanest (no pun intended!) solution would be to store the already cleaned data in the database (either in the same column, or in a separate column), but before I resort to that I thought I'd try and find out whether there's a cleverer way around this.

Non, dans la mesure où les bases de données qui concerne la manière la plus propre est toujours la façon plus intelligente (aussi longtemps que les performances ne sont pas terrible).

Pour ce faire, ajoutez des index aux colonnes que vous comparez en vrac, afin d'améliorer les performances. S'il est intrinsèque au type de données que desc/dated-on/amount est toujours unique, alors exprimez-le dans le schéma en en faisant une contrainte d'index UNIQUE.

0

La façon la plus propre est en effet de se assurer que les données correctes est dans la base de données.

Dans cet exemple, le « BANK.12323.DESCRIPTION » seraient renvoyés par:

SELECT count(*) FROM transactions 
WHERE desc LIKE 'BANK%12323%DESCRIPTION' AND dated_on = ? AND amount = ? 

Mais cela pourrait imposer des problèmes de performance lorsque vous avez beaucoup de données dans le tableau.

+0

Je pense que ce devrait plutôt être 'BANK [. ] 12323 [. ] DESCRIPTION 'pour éviter autant que possible les faux positifs. – Tomalak

1

La méthode la plus simple consiste à ajouter un index unique sur les colonnes appropriées et à utiliser ON DUPLICATE KEY UPDATE. Je recommanderais en outre de transformer le fichier en csv et loading it into a temporary table pour tirer le meilleur parti des fonctions intégrées de mysql, qui sont sûrement plus rapides que tout ce que vous pourriez écrire vous-même - si vous considérez que vous deviez extraire les données dans votre propre application, alors que mysql fait tout en place.

0

Une autre façon que vous pourriez le faire est la suivante:

  • Nettoyer la description avant de l'insérer.

  • Créez une clé primaire pour la table qui est une combinaison des colonnes qui identifient l'entrée de façon unique. On dirait que cela pourrait être nettoyé description, date et montant. Utilisez la syntaxe 'replace' ou 'sur clé dupliquée', ce qui est toujours plus approprié. 'Remplacer' remplace en fait la ligne existante dans la base de la mise à jour d'un lorsqu'une confict clé unique existant se produit, par exemple:

    REPLACE INTO transactions (desc, dated_on, montant)

    (?,??)

    'sur clé en double' vous permet de spécifier les colonnes à mettre à jour sur une double erreur clé: les valeurs

    INSERT INTO transaction (desc, dated_on, montant) sur le montant = montant DUPLICATE KEY SET (?,??)

En utilisant le clé primaire multi-colonnes, vous obtiendrez beaucoup de performance puisque les recherches de clés primaires sont généralement assez rapides.

Si vous préférez conserver votre clé primaire existante, vous pouvez également créer un unix unique sur ces trois colonnes.

Quel que soit votre choix, je vous recommande de nettoyer la description avant d'entrer dans la base de données, même si vous stockez également la description originale et utilisez simplement la description nettoyée pour l'indexation.

Questions connexes