---
title: "Data migration: đi theo object, không đi theo bảng"
url: "https://bahub.vn/khoa-hoc/erp-cho-ba/data-migration-erp"
author: "Võ Văn Trí"
published: "2026-09-10"
updated: "2026-09-29"
source: "bahub.vn"
license: "Được dùng lại, trích dẫn và đưa cho AI đọc, với điều kiện ghi rõ nguồn bahub.vn kèm link bài gốc."
---

# Data migration: đi theo object, không đi theo bảng

> Dữ liệu chủ trước, transaction data sau. Một cột quyết định hệ thống hiểu bạn đang tạo mới hay cập nhật. Và bước đối soát mà mọi checklist đều bỏ qua.

- Nguồn: https://bahub.vn/khoa-hoc/erp-cho-ba/data-migration-erp
- Tác giả: Võ Văn Trí
- Khoá học: ERP cho Business Analyst (mục lục: https://bahub.vn/khoa-hoc/erp-cho-ba.md)
- Chương: Triển khai và vận hành

Tuần đầu sau go-live, kế toán mở báo cáo công nợ ra và thấy một khách hàng có số dư âm. Không ai nhập sai gì trong tuần đó cả; con số sai từ một file Excel được nạp lên hệ thống ba tuần trước, nạp đúng thao tác, không báo lỗi dòng nào.

Đây là loại sự cố có đặc điểm riêng so với mọi sự cố khác trong dự án. Một chức năng chạy sai thì bạn sửa chức năng rồi chạy lại; **một dữ liệu chủ bị khai sai và đã phát sinh giao dịch thì bạn không xóa được nó nữa**, và mọi thứ tham chiếu tới nó đều mang theo cái sai đó.

Do đó phần việc đưa dữ liệu lên hệ thống đáng được tổ chức cẩn thận hơn nhiều so với mức nó thường được đối xử, tức là một việc vặt giao cho người rảnh nhất làm trong hai tuần cuối. Toàn bộ phần cơ chế trong bài này tôi mô tả trên Odoo 19, và đây là loại nội dung bạn phải dựng lại trên đúng bản mình đang chạy chứ không nên tin theo trí nhớ.

![Dữ liệu sai không báo lỗi, chỉ lộ ra khi có người đối chiếu](https://bahub.vn/uploads/2026/09/1790699571060-c36mkw-data-migration-erp-1.webp "Dữ liệu sai không báo lỗi, chỉ lộ ra khi có người đối chiếu")

## Cái giá riêng của sai dữ liệu

Nguyên nhân nằm ở tính liên kết của hệ thống ERP, và cách hiểu dễ nhất là nhìn vào chuyện xóa.

Trong một phần mềm rời rạc, một bản ghi sai thì bạn xóa đi rồi tạo lại. Trong ERP, một bản ghi vừa được tạo là đã có thể bị tham chiếu bởi nhiều nơi khác, và phần lớn các tham chiếu đó được khai báo ở dạng chặn hẳn việc xóa để bảo vệ tính toàn vẹn, chặn cả khi chứng từ đang giữ nó mới chỉ nằm ở trạng thái nháp, bởi ràng buộc ấy sống dưới tầng cơ sở dữ liệu và không hề nhìn vào trạng thái của chứng từ. Từ đó phát sinh một tình huống rất khó chịu: bạn biết dữ liệu sai, bạn biết sửa thế nào, nhưng bạn không có quyền làm việc đó nữa và phải nhờ đội kỹ thuật can thiệp.

Cần lưu ý rằng không phải tham chiếu nào cũng chặn, vì một số trường quan hệ lại được khai báo theo hướng làm rỗng, nghĩa là hệ thống cho bạn xóa rồi để lại ô trống trên toàn bộ chứng từ cũ mà không báo lấy một chữ. Trường hợp còn khó chịu hơn là dữ liệu sai mà không ai biết. Một quyền bị cấp nhầm khiến người không có thẩm quyền nhìn thấy giá bán; một số dư đầu kỳ lệch khiến báo cáo ra sai trong suốt thời gian không ai đối chiếu lại. Cả hai đều là dữ liệu, cả hai đều không báo lỗi, và cả hai chỉ lộ ra khi có người tình cờ đối chiếu.

Vì vậy nguyên tắc tổ chức của bước này không phải là nạp cho nhanh mà là nạp cho đúng thứ tự và đối soát cho kỹ.

## Hai loại dữ liệu và thứ tự nạp

Trong bộ template mà tôi dùng cho dự án Odoo, cột phân loại của danh sách dữ liệu cần đưa lên hệ thống chỉ có hai giá trị là master và transaction data, và quan hệ giữa hai loại đó chỉ đi một chiều vì transaction data trỏ tới master chứ không có chiều ngược lại. Phân biệt này cùng toàn bộ hệ quả của nó lên cách tổ chức một dự án là chủ đề của một bài riêng, còn ở bước nạp dữ liệu thì hệ quả chỉ có đúng một, là **master data phải lên trước rồi transaction data mới lên sau**, bởi một đơn bán hàng không tồn tại được nếu khách hàng và sản phẩm trong đơn chưa có trên hệ thống. Cũng chính vì thế mà bài này nói đi theo đối tượng chứ không đi theo bảng, bởi nếu bạn xuất dữ liệu từ hệ thống cũ ra rồi nạp lần lượt từng bảng theo đúng thứ tự bảng trong hệ thống cũ thì bạn sẽ vấp liên tục, do cấu trúc bảng của hai hệ thống không giống nhau còn quan hệ giữa các đối tượng nghiệp vụ thì giống nhau.

## Thứ tự bên trong master data

Nói master data lên trước thì mới xong một nửa, bởi bản thân các đối tượng trong nhóm này cũng tham chiếu lẫn nhau, và cách dò ra thứ tự đó thuộc bài về hai loại dữ liệu; thứ bạn cần mang sang bước nạp chỉ là kết quả của nó, tức một thứ tự đối tượng đã được chốt trước khi mở file đầu tiên.

Đây cũng là lý do bộ template import theo phân hệ trong tài liệu của tôi được đánh số, và thư mục nào có ràng buộc chặt thì đánh số tới từng file, chẳng hạn bộ import công thức lương gồm năm file được đánh số theo đúng thứ tự phải nạp, bởi các file đầu chính là thứ mà file sau tham chiếu tới. Nạp sai thứ tự ở đó thì hệ thống báo không tìm thấy bản ghi, và bạn mất thời gian đi tìm nguyên nhân ở đúng chỗ không có nguyên nhân.

## Một cột quyết định tạo mới hay cập nhật

Tới phần kỹ thuật quan trọng nhất của bài, và nó chỉ là một cột.

Khi bạn nạp một file lên hệ thống, có một câu hỏi mà hệ thống phải tự trả lời: những dòng này là bản ghi mới, hay là bản ghi đã có và bạn đang muốn sửa. Câu trả lời nằm ở chỗ file của bạn có cột mã định danh ngoài hay không.

**Có cột đó thì hệ thống hiểu đây là cập nhật và ghi đè lên bản ghi tương ứng.** **Không có cột đó thì hệ thống hiểu đây là tạo mới**, và nó tạo thật, nghĩa là nếu bạn định sửa mười nghìn dòng mà quên cột này thì bạn vừa nhân đôi mười nghìn bản ghi.

Cách lấy cột đó cũng đơn giản. Khi xuất dữ liệu ra để sửa, hãy tick lựa chọn nói rằng bạn muốn cập nhật dữ liệu; hệ thống sẽ tự thêm cột mã định danh vào file xuất ra. Sau đó bạn giữ lại đúng cột đó cộng với những cột cần sửa, bỏ hết phần còn lại, rồi nạp ngược lên.

Một tình huống điển hình để thấy giá trị của cách làm này: khách nhập nhầm thuế bán hàng cho mười nghìn mã sản phẩm và muốn bỏ hết. Bạn không sửa tay từng dòng, bạn xuất ra kèm mã định danh, xóa giá trị thuế trên Excel, rồi nạp lại và việc mà làm tay thì không ai làm nổi lại gói gọn trong một vòng xuất và nạp.

![Cột mã định danh quyết định cập nhật hay tạo mới](https://bahub.vn/uploads/2026/09/1790699606812-7f48at-data-migration-erp-2.webp "Cột mã định danh quyết định cập nhật hay tạo mới")

Đồng thời, ngay cả khi tạo mới thì bạn cũng nên tự đặt sẵn cột mã định danh trong file của mình. Không đặt thì hệ thống vẫn tự sinh, nhưng tới lúc phát hiện nạp nhầm và muốn sửa hàng loạt thì bạn lại phải xuất ra để lấy mã, mất thêm một vòng.

## Tự dựng file mẫu khi không có template

Không phải đối tượng nào cũng có sẵn file mẫu, và khi không có thì cách dựng gồm bốn bước.

**Trước tiên, xác định rõ bạn đang định nạp đối tượng nào.** Nghe thừa nhưng đây là chỗ hay lẫn, chẳng hạn giữa sản phẩm và biến thể sản phẩm.

**Tiếp theo, bấm tạo mới hoặc mở một bản ghi đã có ra xem form gồm những trường nào**, và đặc biệt là trường nào bắt buộc. Việc nạp dữ liệu về bản chất giống hệt việc tạo mới bằng tay, nên trường nào bắt buộc khi tạo tay thì cũng bắt buộc khi nạp file.

**Sau đó, xác định tên trường thật.** Cách chắc chắn nhất không phải là đoán theo nhãn hiển thị mà là xuất ngược một bản ghi ra rồi xem đúng tên cột trong file xuất; đó chính là tên bạn cần đặt trong file của mình.

**Và cuối cùng, thêm cột mã định danh ngoài vào file ngay từ đầu**, vì lý do đã nói ở trên.

## Ba loại trường và một cái bẫy về tên

Không phải cột nào cũng nạp giống nhau, và ba loại dưới đây phủ gần hết những gì bạn gặp.

**Trường văn bản (text / char)** là loại dễ nhất, nhập gì cũng vào.

**Trường trỏ tới một đối tượng khác** thì đối tượng đích phải tồn tại sẵn trên hệ thống, nếu không thì khi kiểm tra hệ thống sẽ báo không tìm thấy bản ghi. Lúc đó bạn có hai lựa chọn ngay tại màn hình xem trước, hoặc cho hệ thống tạo luôn bản ghi đích, hoặc bỏ qua dòng đó. Cần lưu ý rằng lựa chọn tạo luôn nghe tiện nhưng nó là cách nhanh nhất để sinh ra dữ liệu chủ rác, bởi cái được tạo chỉ có mỗi cái tên và không có thông tin nào khác.

**Trường thuộc bảng con** thì viết theo dạng tên bảng con kèm dấu gạch chéo rồi tới tên trường, chẳng hạn dòng chi tiết của đơn hàng gồm sản phẩm, số lượng và đơn vị tính. Quy tắc lặp dòng ở đây tiết kiệm rất nhiều công: phần thông tin đầu phiếu chỉ cần ghi ở dòng đầu tiên, các dòng chi tiết tiếp theo của cùng một phiếu để trống phần đó và hệ thống vẫn hiểu chúng thuộc cùng một phiếu.

Cái bẫy nằm ở chính loại thứ hai, và nó liên quan tới cách bạn gọi tên đối tượng đích. Hệ thống chấp nhận nhiều cách, và với những đối tượng như quốc gia thì bạn nhập tên, mã viết tắt hay mã định danh đều được; nhưng khi tên có khả năng trùng thì nạp theo tên là cách chắc chắn để gán nhầm mà không có thông báo lỗi nào, nên với những trường như vậy hãy nạp theo mã. Đồng thời cần lưu ý một quy tắc mà tài liệu chính thức nhấn mạnh: trong cùng một cột thì chỉ được dùng một cơ chế, tức hoặc tất cả theo tên, hoặc tất cả theo mã định danh, chứ không trộn lẫn hai kiểu trong cùng một file.

![Đối soát: giải thích được chênh lệch mới là mục tiêu](https://bahub.vn/uploads/2026/09/1790699638163-pt3o8o-data-migration-erp-3.webp "Đối soát: giải thích được chênh lệch mới là mục tiêu")

## Màn hình xem trước

Trước khi nạp thật thì hệ thống có một màn hình xem trước kèm nút kiểm tra, và đây là bước không được bỏ dù file trông đơn giản tới đâu.

Cách dùng hiệu quả là nạp thử một file rút gọn vài dòng trước, xem hệ thống ánh xạ các cột thế nào, rồi mới nạp toàn bộ. Lý do không phải vì hệ thống chỉ báo được một lỗi, nó trả về cả danh sách, mà vì một cột bị hiểu sai sẽ sinh ra lỗi ở mọi dòng, và một danh sách hàng nghìn dòng lỗi cùng một nguyên nhân thì khó đọc hơn nhiều so với một danh sách năm dòng.

Sau khi nạp xong một đối tượng thì mở ngay vài bản ghi ra xem bằng mắt. Số lượng dòng nạp thành công không nói lên điều gì về việc dữ liệu có vào đúng chỗ hay không, và một cột bị lệch sang trường bên cạnh vẫn cho ra kết quả nạp thành công.

## Đối soát sau khi nạp

Đây là bước phân biệt một lần chuyển dữ liệu xong với một lần chuyển dữ liệu đúng, và cũng là cách làm của riêng tôi chứ không phải một chuẩn có sẵn.

Đối soát nghĩa là đặt cạnh nhau con số trên hệ thống mới và con số trên hệ thống cũ, rồi giải thích được mọi chênh lệch. Ba nhóm số đáng đối soát nhất là:

* tổng số bản ghi của từng đối tượng
* tổng giá trị của những thứ đo được bằng tiền như công nợ phải thu và phải trả
* và tổng số lượng tồn kho theo từng mặt hàng

> Điểm mấu chốt là chênh lệch bằng không không phải mục tiêu, giải thích được mới là mục tiêu. Có những chênh lệch hoàn toàn hợp lý, chẳng hạn hệ thống cũ đang tính gộp một khoản mà hệ thống mới tách ra; cái không chấp nhận được là một chênh lệch mà không ai biết nó từ đâu ra.

Và đối soát phải có người phía khách ký. Không phải vì thủ tục, mà vì con số trên hệ thống cũ là con số mà họ hiểu và bạn thì không; bạn chỉ nhìn thấy hai bảng lệch nhau, còn họ nhìn thấy vì sao lệch.

## Ba việc trước khi coi dữ liệu là xong

Trước khi đóng bước này, hãy kiểm lại ba việc.

* **Việc thứ nhất** là toàn bộ danh sách đối tượng trong bảng dữ liệu đã có trạng thái, và không có dòng nào ở trạng thái chưa rõ.
* **Việc thứ hai** là mỗi đối tượng đã được mở ra xem bằng mắt ít nhất vài bản ghi sau khi nạp.
* **Việc thứ ba** là biên bản đối soát đã có chữ ký của người phía khách hàng, kèm phần giải thích cho mọi chênh lệch còn lại.

Làm xong ba việc đó thì bạn vẫn có thể gặp dữ liệu sai sau go-live, nhưng bạn sẽ có căn cứ để biết cái sai đó đến từ đâu, và đó là khác biệt giữa một buổi xử lý sự cố và một tuần đi tìm nguyên nhân.

Dữ liệu đã lên hệ thống thì việc còn lại là làm cho người dùng biết dùng nó, và đó là chuyện của buổi đào tạo.

---

Nguồn: https://bahub.vn/khoa-hoc/erp-cho-ba/data-migration-erp — Được dùng lại, trích dẫn và đưa cho AI đọc, với điều kiện ghi rõ nguồn bahub.vn kèm link bài gốc.
