Odoo 19 contact import: link companies and update without duplicates
A fictional two-file contact import example using External IDs, with mapping, Test checks and diagnosis of duplicate and relationship errors.

Applicability
Odoo 19; app installation, subscription, access rights and mail configuration must match each workflow. Examples are fictional; UI translations may differ.
Research method
Odoo 19 official documentation research only; no new Odoo product test. Source checks apply only to the scopes listed below.
Keep stable External IDs before importing any contact list. This document-based Odoo 19 guide helps a team choose whether a row should create a company, create a related person or update an existing record. All names below are fictional; no live contact database was used.
Contents
- Decide what each row represents
- Copy a two-file example
- Test a controlled batch
- Update or create: make the choice explicit
- Diagnose the first error before continuing
- Decide whether the full import is ready
Decide what each row represents
A company and its purchasing contact are separate records with a relationship. A second employee is another person, not a replacement name on the company. Agree a naming and ownership rule before cleaning the file: which source is authoritative for company name, email and phone, and who can approve corrections?
For this example, a fictional company has one buyer. We want two records linked together, not two unrelated customers. An External ID identifies a record across imports. It is different from the database's internal numeric ID and should remain stable after the first load.
Copy a two-file example
Company file:
External ID,Name,Is a Company
migration_company_001,Harbour Sample Limited,True
Person file:
External ID,Name,Is a Company,Related Company/External ID,Email
migration_person_001,Alex Sample,False,migration_company_001,alex@example.com
Import companies first, then people. The relationship points to the company's External ID. Use your database's import template or an import-compatible export to confirm available field names and mapping; these headings follow the official 19.0 documentation example, not a guarantee that every translated interface uses the same label.
Test a controlled batch
Open the Contacts list's action menu and choose Import records. Upload the company file, map each column, use Test, and resolve reported errors before Import. Repeat for the person file. Test validates the proposed data; it does not replace checking whether the business relationship is correct.
A useful acceptance check for this fictional batch is exactly two records, with Alex linked to Harbour Sample Limited and the email on Alex's record. Inspect both records before expanding to the full source list. Keep a copy of the original files and record the import mapping and results.
Update or create: make the choice explicit
For an existing Odoo contact, first export the intended record with I want to update data (import-compatible export) enabled. Preserve the supplied External ID and change only the approved fields. Distinguish an omitted column from a mapped blank cell: the official import guide says an explicit empty value clears the field rather than supplying its default. Review blank cells before updating existing contacts. Reimporting the same stable ID updates its record; removing or changing that ID can create duplicates.
A matching name or email is not a reliable substitute for update identity. Do not generate a fresh ID sequence every time the source spreadsheet is saved. If duplicates appear, stop the next batch, identify which rows received new IDs, and compare their dependent quotations or other records before deciding which record should remain.
Diagnose the first error before continuing
| Symptom | Likely question | Next check |
|---|---|---|
| Company relation not found | Was its record imported first? | Confirm the exact company External ID and relation mapping |
| Multiple matches for company name | Is a name being used instead of identity? | Use the intended relation External ID |
| A field is missing from mapping | Did Odoo infer a narrow type from early rows? | Review advanced relation fields and a sample export |
| Chinese names are garbled | Was CSV encoding read correctly? | Check import formatting and the original source text |
| Reimport creates extra contacts | Did External IDs change or disappear? | Compare IDs with the original import-compatible export |
Do not “fix” an import error by deleting a relational column: that can create apparently successful records with missing company links. When correcting an existing batch, an export is useful for review but is not a full database restore. Have an agreed backup and recovery method before large changes; the official import documentation warns that imports cannot simply be undone.
Decide whether the full import is ready
Proceed only when the small batch's record count, identities, company links and approved fields match the worksheet. Keep a batch log of source file, mapping and result so a later update can target the same identities. If the source contains conflicting customer and supplier details, resolve the ownership rule before loading either version.
If migration needs assistance, give APAA the intended record structure and a fictional sample. Start with the relationship and update problem rather than sharing the entire customer list.
Sources
- Export and import data
Company/person CSV example, relation External IDs, Test and update semantics
Source checked