Vierduizend relaties in je boekhouding. Drieduizendzevenhonderd accounts in je webshop. En geen enkel veld dat de twee aan elkaar knoopt, want het ene bestand is aangelegd door een boekhouder en het andere door het bureau dat de shop bouwde.
Zet je de koppeling nu aan zoals hij uit de doos komt, dan heb je maandag zevenduizendzevenhonderd klanten. Niet omdat de koppeling stuk is, maar omdat hij precies doet wat je hem opdroeg: zoeken op een sleutel die er niet is, niets vinden, en aanmaken. Deze gids gaat over de ronde die daarvóór hoort.
Waarom dit begint waar de patroonkeuze ophoudt
Een matchronde is de eenmalige klus waarin je twee bestaande bestanden record voor record aan elkaar knoopt, vóórdat er een koppeling tussen draait. Je matcht in een vaste volgorde op steeds zwakkere velden, verdeelt de uitkomst over zeker, twijfel en nieuw, laat een mens de twijfelgevallen aftekenen, en legt het resultaat vast in een koppeltabel die vanaf dat moment de waarheid is.
Met welk ritme je daarna synchroniseert is een losse beslissing: of je orders event-driven doorduwt en artikelen per nacht in een delta-batch ophaalt hangt af van je datastroom, niet van je bestanden. Wel stelt die keuze een voorwaarde die zo vanzelfsprekend klinkt dat bijna iedereen hem overslaat: een stabiele sleutel per klant, artikel en order, plus een koppeltabel die het id aan de ene kant aan het id aan de andere kant plakt.
Prachtig advies, als je die sleutel nog kunt kiezen. Jij kunt dat niet. Jouw twee bestanden bestaan al, staan allebei vol, en zijn allebei op hun eigen manier vervuild. Precies die ene bullet is waar deze gids begint.
Eén afbakening vooraf. Dubbelen die ontstaan nádat een koppeling een tijd stil lag zijn een ander probleem met een eigen route, waarbij je eerst beide kanten telt op dezelfde sleutel voordat je iets opnieuw aanbiedt. Hier gaat het om de ronde daarvoor, op twee bestanden die die sleutel nog helemaal niet hebben.
Wat je nodig hebt voordat je de eerste rij matcht
Je hebt hiervoor geen matchsoftware nodig, maar zeven dingen die je meestal pas mist als je al bezig bent: een volledige export van beide kanten inclusief het interne id, een plek om te werken die je zelf beheert, een eigenaar per veld, een lege koppeltabel, één mens die mag aftekenen, en een peilmoment waarna er niets meer handmatig bijkomt. Leg ze op tafel voordat je de eerste formule typt.
- Een volledige export van beide kanten, met het interne id als eerste kolom. Niet de weergavenaam, niet het klantnummer dat je zelf ooit bedacht, maar het id waarmee de API het record aanwijst. Zonder dat id kun je je uitkomst nergens terugschrijven.
- Een werkomgeving die je beheert. Dit zijn twee complete klantbestanden. Ze horen niet in een gedeeld sheet in een privé-account en niet op de laptop van een stagiair. Match op zo min mogelijk velden en ruim de werkbestanden achteraf op.
- Per veld één eigenaar, op papier. Welk systeem is de baas over het adres, over het e-mailadres, over de betaaltermijn? Die vraag komt straks terug bij elk verschil dat je vindt, en je wilt hem één keer beantwoorden in plaats van vierhonderd keer.
- Een lege koppeltabel. Zes kolommen: bronsysteem, bron-id, doelsysteem, doel-id, hoe gematcht, door wie en wanneer. Een sheet mag, zolang hij daarna verhuist naar iets wat je koppeling kan bevragen.
- Eén mens die de twijfelgevallen aftekent. Iemand die de klantnamen herkent, dus uit de verkoop of de administratie. Dit is de rol die het vaakst wordt ingevuld met "dat doet de stagiair er even bij", en dat is precies waar het misgaat.
- Een budget voor verrijking, als een sleutelveld grotendeels leeg is. Bij de KVK betaal je een abonnement van 6,40 euro per maand, waarbij de Zoeken-API nul euro per bevraging kost en een profielbevraging twee cent (tarieven augustus 2026, vrijgesteld van btw).
- Een peilmoment. Vanaf dat tijdstip komen er aan beide kanten geen handmatig aangemaakte records meer bij. Duurt je matchronde drie dagen en typt de verkoop ondertussen door, dan match je een bestand dat niet meer bestaat.
De matchronde: vijf velden, van hard naar zacht
De volgorde is het hele ontwerp. Je begint met het veld dat een record echt identificeert en zakt af naar velden die alleen maar suggereren. Elke stap kijkt uitsluitend naar wat de vorige liet liggen, want een record dat al zeker gekoppeld is doet niet meer mee. Zo krijgt je zwakste bewijs de kleinste stapel in plaats van de hele berg.
1. Normaliseer in een kolom ernaast, nooit over de bron heen
Voordat je iets vergelijkt maak je van elk matchveld een schoongepoetste kopie. Kleine letters, spaties weg, punten en streepjes weg, diakritische tekens weg. Rechtsvormen eruit bij de naam: B.V., bv, Holding, VOF, Beheer. Adres splitsen in straat, huisnummer en toevoeging, want "Dorpsstraat 12 A" en "Dorpsstraat 12A" zijn hetzelfde adres en verschillende tekst.
Dat schoonmaken gebeurt in nieuwe kolommen. De brongegevens blijven staan zoals ze zijn, want die ga je straks terugschrijven en niemand wil een klant die voortaan "bakkerij jansen" heet.
Wil je hier gereedschap bij: OpenRefine doet dit als los product en beschrijft zijn eigen fingerprint-methode (kleine letters, leestekens eruit, woorden alfabetisch sorteren) als de methode die het minst snel valse positieven oplevert. De n-gram-variant vindt méér, maar levert er ook meer onterecht op. Dat is exact de afweging die je hierna bij elke stap maakt.
2. Match op KvK-nummer
Het hardste veld dat je in Nederland hebt. Een KvK-nummer bestaat uit acht cijfers en wijst een inschrijving in het Handelsregister aan; een vestigingsnummer heeft er twaalf en wijst één specifieke vestiging aan. Dat verschil is geen detail: een bedrijf met vijf filialen heeft één KvK-nummer en vijf vestigingsnummers. Factureer je per filiaal, dan klapt een match op KvK-nummer die vijf klanten tot één.
De valkuil is niet het matchen maar de dekking. Een KvK-nummer staat alleen in je bestand als je er ooit om hebt gevraagd, en in een webshop is dat zelden. Is het veld grotendeels leeg, dan vul je het aan vóórdat je matcht: de Zoeken-API van de KVK accepteert naam, straatnaam, postcode, huisnummer en plaats als zoekcriteria en geeft maximaal honderd resultaten per pagina terug. Een aanvulronde op naam plus postcode kost je een middag en verplaatst honderden records van de zachte naar de harde stap.
3. Match op btw-identificatienummer
Een Nederlands btw-id ziet eruit als NL, negen cijfers, de letter B en twee cijfers. Bij een rechtspersoon zijn die negen cijfers het RSIN, dat ook uit het Handelsregister komt, en dat maakt dit veld een bruikbare brug terug naar stap 2.
Nu de val. Het btw-identificatienummer is niet hetzelfde als het omzetbelastingnummer, en het verschil is niet cosmetisch: bij een zzp'er bestaat het omzetbelastingnummer uit de negen cijfers van zijn burgerservicenummer, terwijl het btw-id die juist niet bevat. Staan er in je oude bestand nog nummers van de eerste soort, dan matchen ze niet op de tweede én heb je een bsn in een veld waar het niet hoort. Zet die records apart in plaats van ze mee te matchen.
Valideren kan gratis via VIES van de Europese Commissie, maar verwacht er geen verrijking van: die dienst controleert of een nummer geldig is en geeft om privacyredenen geen naam en adres terug. Je kunt een btw-id dus bevestigen, niet omzetten in een bedrijfsnaam.
4. Match op e-mailadres
Hier begint het zachte werk. Een e-mailadres is geen sleutel, want mensen wisselen ze, delen ze en hebben er drie. Toch levert deze stap in de praktijk vaak de grootste stapel op, simpelweg omdat het het enige veld is dat beide systemen altijd hebben.
Twee regels houden hem schoon. Gedeelde postbussen (info@, administratie@, verkoop@, factuur@) zijn nooit een zekere match, want twee vestigingen van dezelfde keten gebruiken hetzelfde adres. Die gaan rechtstreeks naar de twijfelbak. En match je op domein in plaats van op het volledige adres, sluit dan de gratis maildiensten uit; anders knoop je vierhonderd klanten aan elkaar omdat ze allemaal bij gmail.com zitten.
Draai je aan één kant HubSpot, dan is een deel van dit werk al gedaan: dat systeem ontdubbelt contacten automatisch op e-mailadres en bedrijven op domeinnaam. Dat helpt binnen HubSpot en zegt niets over de match met je andere systeem, maar het scheelt je wel een ronde aan die kant. Hoeveel een pakket hier zelf al voor je doet verschilt sterk, en het is één van de punten waarop HubSpot, Pipedrive en Salesforce uiteenlopen.
5. Match op postcode plus huisnummer
In Nederland is de combinatie postcode en huisnummer bijna een adressleutel, en dat "bijna" doet al het werk. Drie dingen breken hem.
Een bedrijvenverzamelgebouw waar veertig bedrijven op hetzelfde adres staan ingeschreven. Een postbus die in het ene systeem als adres staat en in het andere niet. En de huisnummertoevoeging, die in het ene bestand een eigen kolom heeft en in het andere achter het huisnummer is geplakt.
De regel is daarom: postcode plus huisnummer alleen is nooit zeker. Combineer hem altijd met een naamgelijkenis boven een vaste drempel. Komt het adres overeen maar de naam niet, dan is dat geen match maar een twijfelgeval, en vaak zelfs een terecht apart record. Let er ook op welk adres je vergelijkt: het factuuradres van je boekhouding en het afleveradres van je webshop zijn twee verschillende velden die toevallig allebei "adres" heten.
6. Match op genormaliseerde naam, en nooit automatisch
De laatste stap, op de kleinste stapel, en de enige die per definitie niets zekers oplevert. Je vergelijkt de opgeschoonde namen met een tekstafstand: Levenshtein voor korte namen, een woordgebaseerde methode voor lange. Wat boven je drempel scoort is een kandidaat.
Een kandidaat is geen match. "Bakkerij Jansen B.V." en "Bakkerij Jansen Holding B.V." scoren bijna gelijk en zijn twee juridische entiteiten met twee aparte facturen. Alles wat hier uitkomt gaat naar de twijfelbak, zonder uitzondering. Draai je deze stap per ongeluk als eerste, dan vervuil je je hele uitkomst en merk je het pas als de verkeerde klant een aanmaning krijgt.
7. Wat overblijft is nieuw, en krijgt meteen een sleutel
Records die zes stappen hebben overleefd zonder enige match zijn nieuw. Maak ze aan, en schrijf ze in dezelfde beweging in de koppeltabel. Een nieuw record zonder rij in de koppeltabel is het begin van het volgende dubbelenprobleem.
| Veld | Wat het echt identificeert | Dekking in een mkb-bestand | Waar het je bedriegt | Verdict |
|---|---|---|---|---|
| KvK-nummer (8 cijfers) | de inschrijving, niet de vestiging | laag, alleen als je erom vroeg | filialen klappen samen tot één klant | zeker |
| Btw-id (NL + 9 + B + 2) | de btw-plichtige entiteit | midden bij B2B, nul bij consumenten | het omzetbelastingnummer lijkt erop en bevat een bsn | zeker |
| E-mailadres | een postbus, geen persoon | hoog | info@ en andere gedeelde adressen | zeker, behalve gedeelde adressen |
| Postcode plus huisnummer | een adres, geen bedrijf | hoog | verzamelgebouw, postbus, toevoeging | alleen mét naamgelijkenis |
| Genormaliseerde naam | niets, het suggereert alleen | hoog | holding tegenover werkmaatschappij | altijd twijfel |
Drie bakken: zeker, twijfel, nieuw
Twee drempels, geen één. Dat is de belangrijkste ontwerpkeuze in deze hele gids, want met één drempel dwing je jezelf om elk grensgeval automatisch een kant op te duwen.
- Zeker is: één harde identificator exact gelijk (KvK-nummer of btw-id), óf twee onafhankelijke zachte velden die elkaar bevestigen (uniek e-mailadres én adres, of adres én naam boven de drempel). Deze rijen gaan automatisch de koppeltabel in.
- Twijfel is: één zacht veld gelijk zonder tweede bevestiging, of meerdere kandidaten aan de andere kant. Deze rijen wachten op een mens.
- Nieuw is: geen enkele match, op geen enkel veld. Aanmaken, met sleutel.
Werk je met een scoresysteem in plaats van met regels, dan geldt precies hetzelfde in getallen: zet twee drempels, en de band ertussen ís je twijfelbak. Zo werkt het ook bij het zwaardere gereedschap. Het Britse ministerie van Justitie beschrijft in zijn transparantieverslag over de koppelsoftware Splink dat recordparen boven een ingestelde drempel als dezelfde persoon gelden, en dat in de toepassingen waarin een lijst met mogelijke matches aan een mens wordt voorgelegd, die mens de eindbeslissing neemt (verslag oktober 2025).
Waarom die scheefheid? Omdat de twee fouten niet even duur zijn. Een gemiste match levert een dubbele klant op: vervelend, zichtbaar, en later te repareren. Een onterechte match voegt twee klanten samen, en dat is bij vrijwel elk pakket definitief. Zet je drempels dus zo dat twijfel naar de mens gaat en niet naar de automaat.
De twijfelbak: één mens, één zitting, klein gehouden
Iedereen die dit werk beschrijft komt bij een handmatige controle uit, en iedereen die het uitvoert loopt vast op dezelfde reden: de bak wordt te groot en blijft daarna openstaan. Vijf dingen houden hem klein.
Sorteer op geld, niet op alfabet. Verrijk je twijfellijst met de omzet of het aantal orders van de afgelopen twaalf maanden en werk van boven naar beneden. De klanten die je administratie herkent staan bovenaan, en dat zijn precies de records waar een verkeerde koppeling geld kost.
Toon zes kolommen, niet het hele record. Naam links, naam rechts, adres, e-mail, laatste order, en waarom het systeem twijfelt. Meer informatie maakt de beslissing niet beter, alleen trager.
Geef drie knoppen. Zelfde, niet zelfde, weet ik niet. Die derde is essentieel: "weet ik niet" betekent apart aanmaken met een vlag, niet samenvoegen. Twijfel mag nooit stilzwijgend een match worden.
Zet er een einddatum op. Eén zitting, een afspraak in de agenda, twee tot vier uur. Een twijfelbak zonder deadline verandert binnen twee weken in een tweede achterstand.
Bewaar elke beslissing. Elke afgetekende rij is een voorbeeld waarmee je je regels aanscherpt, en bij lerende bibliotheken zoals dedupe en Splink is het letterlijk trainingsmateriaal. De tweede keer dat je dit doet, en die komt, is je bak de helft kleiner.
En een maat om jezelf mee te corrigeren: is je twijfelbak groter dan vijf procent van het kleinste bestand, dan zijn je drempels verkeerd, niet je data. Loop de volgorde van je stappen na voordat je iemand door duizend rijen laat klikken.
Survivorship: welk systeem wint welk veld
Twee records zijn gematcht en ze spreken elkaar tegen. Welke waarde gaat de gouden versie in? Dat heet survivorship, en de fout die iedereen maakt is dat je het per systeem beslist ("het CRM is leidend") in plaats van per veld. Geen enkel systeem is overal het beste in. Je boekhouding weet niet welke contactpersoon vorige week vertrok; je webshop weet niet welk btw-regime geldt.
| Veld | Wie wint | Waarom |
|---|---|---|
| Bedrijfsnaam en rechtsvorm | het Handelsregister | dit is de naam die op de factuur hoort, niet de naam die iemand ooit typte |
| Factuuradres | de boekhouding | daar staat het adres waarop de laatste factuur is geaccepteerd |
| Afleveradres | het systeem dat verzendt | de webshop of het magazijn weet waar het pakket echt heen ging |
| E-mailadres | het systeem waar de klant het zelf wijzigt | zelfbediening is verser dan wat een collega ooit intikte |
| Btw-id en btw-regime | de boekhouding | dit is het veld waarop je gecontroleerd wordt |
| Betaaltermijn en kredietlimiet | de boekhouding | het is geld, en het is daar afgesproken |
| Eigenaar, segment, notities | het CRM | daar leeft de relatie, niet de administratie |
| Telefoonnummer | geen natuurlijke eigenaar | val terug op de ladder hieronder |
Voor velden zonder eigenaar gebruik je een vaste ladder, in deze volgorde: gevuld wint van leeg, gevalideerd wint van ongevalideerd, recentst gewijzigd wint van ouder, en pas daarna wint de volledigste waarde van de kortere.
Op die derde tree zit de klassieke val. "Recentst gewijzigd" zegt alleen iets als die tijdstempel een menselijke wijziging weerspiegelt. Eén bulkimport uit 2024 heeft alle tijdstempels aan één kant opgehoogd, en dan wint dat systeem voortaan alles, ook de velden waar het niets van weet. Kijk dus naar de verdeling van je wijzigingsdata voordat je deze regel aanzet: staan er duizend records op exact dezelfde seconde, dan is dat geen wijziging maar een import.
De koppeltabel is vanaf nu de waarheid
Uit de matchronde rolt geen samengevoegd bestand maar een tabel. Eén rij per koppel: bronsysteem, bron-id, doelsysteem, doel-id, op welk veld gematcht, met welke zekerheid, door wie afgetekend en wanneer. Die tabel is vanaf dat moment het antwoord op de vraag "is deze klant al bekend", en de koppeling stelt die vraag vóór elke schrijfactie.
Waar hij woont bepaalt of hij standhoudt. Drie werkbare plekken (de veldlimiet en het API-gedrag hieronder gecontroleerd augustus 2026):
- In je integratielaag, als eigen tabel in de database van je koppeling. De schoonste optie, want daar hoort hij.
- In beide systemen, als uniek veld. In HubSpot kun je maximaal tien eigen velden per objecttype uniek maken, en zo'n veld is de natuurlijke plek voor het id van de andere kant.
- In één systeem, als het al een uniek sleutelveld heeft. In Exact Online is dat Account.Code: een uniek numeriek veld van achttien tekens met voorloopspaties, en die voorloopspaties moet je in je OData-filter meegeven, anders vindt je koppeling niets terwijl het record er gewoon staat.
Drie regels houden de tabel gezond. Verwijder er nooit rijen uit: voeg je later twee records samen, dan blijft het oude id bestaan als alias-rij, want er lopen nog orders en facturen die ernaar verwijzen. Schrijf de reden mee: over een jaar wil je kunnen zien of een koppeling automatisch of met de hand tot stand kwam. Laat de koppeling hem lezen, niet raden: zoek op de sleutel, en maak alleen aan als de tabel niets teruggeeft.
Artikelen en SKU's: drie nummers voor één product
Bij klanten zoek je één identiteit. Bij artikelen heb je er standaard drie: jouw eigen artikelnummer, het artikelnummer van je leverancier, en de GTIN of EAN op de verpakking. Ze verwijzen naar hetzelfde product en ze zijn geen van drieën inwisselbaar.
Match daarom in deze volgorde. GTIN eerst, want dat is het enige nummer dat noch van jou noch van je leverancier is. Dan leverancier plus leveranciersartikelnummer, altijd als paar, want twee leveranciers gebruiken vrolijk allebei nummer 1001. Dan pas je eigen artikelnummer, en nooit de omschrijving; "blauw t-shirt maat M" bestaat in elk bestand in vier spellingen.
Drie dingen breken de artikelmatch die bij klanten niet spelen.
Varianten. Het ene systeem bewaart kleur en maat als opties onder één product, het andere als losse regels. Je match is dan één-op-veel en je koppeltabel moet dat aankunnen. Belangrijker nog: elke variant die een klant of ketenpartner van de andere kan onderscheiden is een eigen handelsartikel, en volgens GS1 wijs je een nieuwe GTIN toe zodra klanten of ketenpartners het gewijzigde product van het huidige kunnen onderscheiden, er een wettelijke informatieplicht ontstaat, of het gevolgen heeft voor hoe het product wordt verzonden, opgeslagen of ontvangen.
Verpakkingseenheden. Je webshop verkoopt per stuk, je voorraadsysteem boekt per doos van twaalf. Match je die twee zonder conversiefactor, dan is je voorraad een factor twaalf mis en merk je het pas bij de inventarisatie. De koppeltabel krijgt hier dus een extra kolom: hoeveel eenheden van links passen in één eenheid van rechts. In de handelsniveaus van GS1 is dat overigens netjes geregeld: alle stuks in een standaard omdoos dragen dezelfde GTIN, terwijl een gemengde doos er per definitie meer dan één bevat.
Vervangen artikelen. Een leverancier stopt met een nummer en brengt een opvolger uit. Dat is geen match maar een opvolgrelatie, en die hoort in een eigen kolom, niet in je koppeltabel. Anders verdwijnt je verkoophistorie op het oude nummer.
De dubbelen die er nu al staan, zonder je historie te breken
Eén principe: samenvoegen, nooit verwijderen. Een relatie met facturen wis je niet, want dan wis je de tegenhanger van boekingen die je zeven jaar moet kunnen tonen. Wat de pakketten in deze sectie precies doen, HubSpot, Exact en Moneybird, is gecontroleerd in augustus 2026; dit is het soort gedrag dat een leverancier zonder aankondiging wijzigt, dus check het opnieuw voordat je op de knop drukt.
Zet ook eerst de kraan dicht. Zolang er nog een route bestaat waarlangs dubbelen ontstaan, ruim je zand op tijdens een zandstorm. De meest onderschatte route is de import: Moneybird schrijft er onomwonden bij dat je bestaande contacten niet via een import kunt bijwerken en dat een nieuwe import dubbele contacten aanmaakt. "Ik zet de schone lijst er gewoon overheen" is dus precies hoe je je bestand verdubbelt.
Weet daarna wat samenvoegen in jouw pakket écht doet, want dat verschilt en het is overal definitief:
- HubSpot laat de eigenschappen van het hoofdrecord winnen, vult lege velden aan uit het andere, en zet alle activiteiten en gekoppelde records bij elkaar. Terugdraaien kan niet, en bij een gecombineerd totaal van 250 samenvoegingen weigert het systeem het record verder samen te voegen. Het nieuwe record krijgt een nieuw id; de oude id's blijven bewaard in een eigen veld.
- Exact Synergy Enterprise heeft er een batchfunctie voor, en let op het product: je draait daar eerst een Voorbeeld dat een rapport oplevert van wat er gaat gebeuren, en Exact vermeldt erbij dat het proces niet ongedaan gemaakt kan worden. De criteria die je daar kunt aanvinken zijn precies de velden uit deze gids: gestripte naam, postcode, e-mailadres, btw-nummer en KvK-nummer. In Exact Online loopt het anders, per relatie: je opent de relatie en klikt op Ontdubbelen. Draait er al een koppeling, werk dan meteen je koppeltabel bij, want een koppeling die nog het bij het ontdubbelen verdwenen relatie-id gebruikt, krijgt zijn orders niet meer geïmporteerd.
- Moneybird verplaatst alle documenten naar het contact dat je bewaart, maar past de gegevens op de facturen zelf niet aan, en documenten die in een afgesloten periode vallen verhuizen niet mee.
Dat laatste punt is meteen het antwoord op de angst dat je je historie breekt. Een verstuurde factuur is een momentopname en hoort dat te blijven: de naam en het adres van toen zijn onderdeel van het document. Samenvoegen verandert wie de klant nú is, niet wat je toen hebt gefactureerd. Wat je wél nakijkt zijn de lopende dingen: openstaande orders, abonnementen, incassomandaten en herhaalfacturen die nog aan het verdwijnende record hangen.
Praktisch: werk in blokken van vijftig, exporteer beide records naar een bestand voordat je op samenvoegen drukt (er is geen ongedaan maken, dus dat bestand is je enige weg terug), en houd de verdwenen id's in je koppeltabel als alias.
Waar het misgaat
Acht faalmodi, elk met de mitigatie erbij. Ze komen alle acht voor bij mensen die dachten dat ze een halve dag bezig waren.
- De naamstap als eerste draaien. Alles wat erna komt bouwt voort op vervuiling. Mitigatie: naam is de laatste stap, altijd, en alleen op de rest.
- Eén record links dat drie kandidaten rechts heeft. De hoogste score pakken is gokken. Mitigatie: forceer één-op-één, haal een gematcht paar aan beide kanten uit de pool, en stuur meervoudige kandidaten ongezien naar de twijfelbak.
- Normaliseren over de bron heen. Je hebt je klantnamen in kleine letters teruggeschreven. Mitigatie: normaliseer in kolommen ernaast, altijd.
- Gratis maildomeinen in een domeinmatch. Vierhonderd klanten aan elkaar geknoopt omdat ze bij dezelfde provider zitten. Mitigatie: een uitsluitlijst van publieke maildiensten, en gedeelde postbussen naar de twijfelbak.
- Postbus tegen bezoekadres. Twee records van dezelfde klant matchen niet omdat het ene systeem het postadres bewaart. Mitigatie: vergelijk adrestype met adrestype, en probeer beide varianten.
- Survivorship op tijdstempels die van een import komen. Eén systeem wint plots alles. Mitigatie: controleer de verdeling van je wijzigingsdata voordat je die regel aanzet.
- De twijfelbak zonder eigenaar en zonder datum. Hij wordt een permanente wachtrij en over een half jaar durft niemand hem meer aan te raken. Mitigatie: één naam, één zitting, één einddatum.
- Twee complete klantbestanden in een privésheet. Dit is een verwerking van persoonsgegevens, ook als het "even snel" is. Mitigatie: match in een omgeving die je beheert, met zo min mogelijk velden, en ruim de werkbestanden op als je klaar bent.
Zelf doen, gereedschap of maatwerk
Vier routes, en de omvang van het kleinste bestand bepaalt welke past. Onder ongeveer tweeduizend records is dit handwerk met hulpmiddelen; boven de twintigduizend is handwerk geen optie meer.
| Route | Kosten | Doorlooptijd | Sterk bij | Loopt stuk op |
|---|---|---|---|---|
| Ontdubbelfunctie van je pakket (Exact, HubSpot, Moneybird) | zit in je abonnement | uren | opruimen binnen één systeem | werkt niet tussen twee systemen |
| Spreadsheet plus OpenRefine | open source, geen licentiekosten | een tot drie dagen | tot ongeveer tienduizend rijen, eenmalig | herhaalbaarheid, en scores ontbreken |
| Record-linkage-bibliotheek (Splink, dedupe) | open source, plus een paar dagen werk van iemand die Python kan | drie tot vijf dagen | tienduizenden rijen, echte drempels, herhaalbaar | vraagt technische kennis in huis |
| Matchdienst in de koppeling zelf | een project | weken | doorlopende instroom aan beide kanten | overkill bij een eenmalige klus |
De eerlijke grens: is dit een eenmalige klus en telt je grootste bestand vierduizend regels, dan is dit dagen werk, geen weken, en zeker geen aanleiding om een masterdatapakket te kopen. Wordt matchen daarentegen doorlopend werk, omdat aan beide kanten nieuwe klanten binnenstromen die je niet vooraf kunt afdwingen, dan verhuist de logica naar de koppeling en is het bouwwerk. De rekensom die daaronder hoort is dezelfde als bij elke andere koppeling: naast de bouw tellen ook het onderhoud en het verbruik mee.
Hoeveel klantrecords staan er aan de kleinste kant?
Een rekenvoorbeeld: 4.000 relaties in Exact, 3.700 in de webshop
Neem een groothandel met een B2B-webshop. In Exact Online staan 4.000 relaties, waarvan een deel leveranciers en oude klanten. In de webshop staan 3.700 accounts. Dit zijn cijfers uit een voorbeeld en geen meting, maar de verhoudingen zijn herkenbaar.
De matchronde loopt op de 3.700 webshopaccounts, en elke stap kijkt alleen naar wat overblijft:
- KvK-nummer: 1.150 zeker. Het B2B-portaal vraagt erom bij registratie, dus voor de nieuwere klanten is het veld gevuld. Blijft over: 2.550.
- Btw-id: 240 zeker. Er komen ook 40 records boven met een nummer in de oude vorm, met een bsn erin; die gaan apart en worden opgeschoond in plaats van gematcht. Blijft over: 2.310.
- E-mailadres: 980 zeker. 60 adressen zijn gedeelde postbussen (info@ bij ketens met meerdere vestigingen) en gaan naar de twijfelbak. Blijft over: 1.270.
- Postcode plus huisnummer, mét naamgelijkenis: 420 zeker. 95 records delen een adres in twee bedrijvenverzamelgebouwen en gaan naar de twijfelbak. Blijft over: 755.
- Genormaliseerde naam: 165 kandidaten, allemaal naar de twijfelbak. Blijft over: 590.
De uitkomst: 2.790 zeker, 320 twijfel, 590 nieuw. De 320 twijfelgevallen worden gesorteerd op omzet over twaalf maanden; de bovenste honderd zijn klanten die de administratie bij naam kent en die gaan er in een uur doorheen. De rest kost nog een uur.
Eindstand na de ronde: 4.590 relaties in Exact (de 590 nieuwe erbij), een koppeltabel van 3.700 rijen, één per webshopaccount, want ook elk nieuw record krijgt in stap 7 meteen zijn rij, en 890 Exact-relaties zonder tegenhanger: leveranciers en klanten die nooit online hebben besteld. Geen 7.700.
Die eindstand gaat ervan uit dat de administratie alle 320 twijfelgevallen als "zelfde" aftekent. Elk geval dat op "niet zelfde" of "weet ik niet" uitkomt wordt een eigen nieuw record met een vlag en verschuift de telling met één: de koppeltabel houdt zijn 3.700 rijen, maar Exact telt er een relatie bij en er blijft er een extra zonder tegenhanger. Eindigen er twintig zo, dan staat er 4.610 tegenover 910.
De artikelkant loopt parallel: 2.100 artikelen tegen 1.850 webshopproducten. De GTIN-stap matcht er 1.400, leverancier plus leveranciersnummer nog eens 300, en de resterende 150 gaan met de hand omdat het eigen samenstellingen zijn zonder barcode. Bij 40 producten verkoopt de webshop per stuk terwijl Exact per doos van twaalf boekt; die krijgen een conversiefactor in een eigen kolom. Dat zijn 40 regels die anders je hele voorraadtelling onbruikbaar hadden gemaakt.
Doorlooptijd: twee dagen voorbereiden en matchen, een halve dag aftekenen, een dag terugschrijven en controleren. Daarna staat er een sleutel waar er eerst geen was, en dat is het enige wat de koppeling ooit van je vroeg.
Tot slot
De verleiding bij twee volle bestanden is om de koppeling te laten uitzoeken wie wie is. Dat is precies de verkeerde volgorde: een koppeling is een uitvoerder, geen rechter. Ze kan alleen doen wat jij hebt vastgelegd, en heb je niets vastgelegd, dan doet ze het enige wat overblijft, namelijk aanmaken.
De matchronde is daarom geen voorbereidend werk maar de beslissing zelf. Je bepaalt één keer, met bewijs en met een mens erbij, wie dezelfde klant is en wie niet. Wat eruit rolt is geen schoon bestand maar iets wat langer meegaat: een sleutel, plus de afspraak dat niemand er meer omheen werkt. Alles wat je daarna koppelt wordt saai. Dat is het doel.
Veelgestelde vragen
Twee bestanden, één waarheid
Ik denk met je mee over welk systeem welk veld bezit, ontwerp de matchronde en bouw de koppeltabel en de synchronisatie er end-to-end omheen. Zo begint je koppeling met een sleutel in plaats van met dubbelen.
Dit artikel is geproduceerd samen met het Agent Team. Meer over de redactie.
