zalo-icon
facebook-icon
phone-icon
dbt là gì? Vì sao biết SQL rồi vẫn cần dbt? | Bài 1/10

Series dbt: Xây dựng Data Warehouse từ SQL đến dự án thực tế · Bài 1/10. Bạn đã biết SELECT, JOIN và GROUP BY. Một ngày, kế toán và marketing cùng hỏi doanh thu tháng này nhưng hai báo cáo trả hai con số khác nhau. Vấn đề có thể không nằm ở cú pháp SQL: mỗi người lọc trạng thái đơn khác nhau, join làm nhân số dòng, hoặc chạy lại một đoạn script cũ.

dbt giúp tổ chức việc biến đổi dữ liệu thành một dự án có cấu trúc, phụ thuộc rõ ràng, kiểm thử và tài liệu. Tuy nhiên, nó không tự quyết định doanh thu là gì và cũng không tự sửa dữ liệu sai. Bài đầu sẽ đi từ tình huống bán hàng tới một lab SQL nhỏ, để bạn hiểu chính xác phần công việc dbt đảm nhận trước khi cài đặt ở bài 2.

1. Bắt đầu từ câu hỏi doanh nghiệp

Một cửa hàng có đơn đã thanh toán, đơn bị hủy và đơn đang chờ. “Tổng giá trị đơn hàng được tạo” và “doanh thu của đơn đã thanh toán” là hai chỉ tiêu khác nhau. Cộng tất cả amount rồi gọi đó là doanh thu khiến báo cáo dễ hiểu sai dù câu SQL vẫn chạy thành công. Trước khi chọn công cụ, cần viết một câu định nghĩa đủ rõ để người khác kiểm chứng.

Trong năm bài đầu, quy ước đơn giản của lab là: doanh thu bán hàng bằng tổng quantity nhân unit_price_vnd của những dòng hàng thuộc đơn có trạng thái paid. Chưa tính thuế, phí giao hàng, chiết khấu, hoàn tiền hay thời điểm ghi nhận kế toán. Đây là chỉ tiêu phục vụ học mô hình dữ liệu, không phải chuẩn doanh thu áp dụng mặc định cho mọi doanh nghiệp.

Một định nghĩa chỉ tiêu chung giúp các nhóm đối chiếu cùng một kết quả.
Một định nghĩa chỉ tiêu chung giúp các nhóm đối chiếu cùng một kết quả.

Giả sử marketing nhận đơn từ website còn kế toán nhận thanh toán từ ngân hàng. Hai nguồn còn có thể khác thời điểm cập nhật. Một dự án tốt cần phân biệt lỗi logic, dữ liệu đến muộn và khác định nghĩa nghiệp vụ. Chỉ chuyển code sang dbt chưa làm ba vấn đề đó biến mất; lợi ích là bạn có nơi ghi lại quy tắc và chạy kiểm tra nhất quán.

2. dbt làm gì và chạy ở đâu?

Với SQL model, bạn viết câu SELECT mô tả bảng hoặc view muốn có. dbt phân tích cấu hình, giải quyết các tham chiếu giữa model, biên dịch SQL rồi gửi câu lệnh đến nền tảng dữ liệu qua adapter. PostgreSQL mới là nơi thực thi phép JOIN hay GROUP BY và giữ bảng kết quả. dbt không tải toàn bộ dữ liệu về Python để tính như một script pandas.

Có thể hình dung transformation như căn bếp: nguyên liệu đã có, quy trình tạo ra món phục vụ người dùng.
Có thể hình dung transformation như căn bếp: nguyên liệu đã có, quy trình tạo ra món phục vụ người dùng.
Khái niệmHiểu trong dự án bán hàngĐiểm cần phân biệt
Warehouse / databasePostgreSQL giữ bảng nguồn và bảng phân tíchNơi dữ liệu được lưu và SQL thực thi
ModelFile SQL mô tả dữ liệu muốn xâyMột model không nhất thiết là một bảng vật lý
MaterializationCách xây model thành view, table hoặc dạng khácQuyết định khi nào dữ liệu được tính và lưu
Adapterdbt-postgres kết nối dbt với PostgreSQLKhông phải mọi SQL đều giống nhau giữa các database
DAG / lineageQuan hệ model nào cần kết quả model nàoGiúp chọn đúng thứ tự và đánh giá tác động thay đổi
Data testTruy vấn phát hiện dòng vi phạm quy tắcKhông tự sửa hoặc chặn mọi lỗi có thể xảy ra

Trong một pipeline ELT, bước Extract lấy dữ liệu từ hệ thống nguồn; Load đưa dữ liệu vào nơi phân tích; Transform chuẩn hóa và tạo bảng phục vụ báo cáo. Series tập trung phần Transform. Kafka, Debezium hoặc công cụ ingestion có thể làm phần phía trước; dbt đọc dữ liệu đã có trong database. Seeds là ngoại lệ thực hành cho CSV nhỏ hoặc dữ liệu tham chiếu, không phải giải pháp ingestion dung lượng lớn.

Tên dbt hiện có nhiều lựa chọn sản phẩm và runtime. Series này dùng dbt Core dòng 1.x chạy local với adapter PostgreSQL, để người học nhìn được file cấu hình và câu lệnh. Không cần tài khoản dịch vụ cloud để theo lab. Khi xem tài liệu mới, hãy chọn đúng phiên bản vì hướng dẫn cho runtime khác có thể có lệnh cài và tính năng khác.

3. Có SQL rồi, vì sao còn cần dbt?

SQL giải quyết cách biến đổi dữ liệu. Một dự án còn cần trả lời: file nào chạy trước, kết quả nằm ở schema nào, ai sửa logic, điều gì cần kiểm tra và báo cáo nào bị ảnh hưởng? Bạn có thể tự xây những khả năng đó bằng script, stored procedure, Git và scheduler. dbt cung cấp một hệ quy ước để cả nhóm không phải thiết kế lại tất cả từ đầu.

Tiêu chíSQL script / stored procedureDự án dbt
Logic biến đổiViết SQL trực tiếp hoặc đóng gói trong databaseSQL model cùng cấu hình và macro khi cần
Thứ tự chạyTự quản lý bằng script hoặc công cụ điều phốiKhai báo phụ thuộc bằng ref()/source()
Kiểm tra dữ liệuTự tạo truy vấn, quy trình và cách báo lỗiTest là tài nguyên trong project
Tài liệuTự giữ đồng bộ với codeMô tả model/cột có thể đi cùng project và lineage
Lập lịchScheduler, cron, Airflow hoặc nền tảng khácdbt Core CLI cần được gọi bởi một cơ chế lập lịch
Chi phí vận hànhÍt thành phần khi bài toán nhỏThêm cấu trúc, dependency và quy trình cần quản lý

Stored procedure phù hợp cho nhiều bài toán thao tác dữ liệu, transaction hoặc logic nằm sát database. dbt thường thuận lợi khi nhóm xây nhiều bảng phân tích có phụ thuộc và cần cùng phát triển bằng Git. Đây không phải cuộc thi công cụ nào thay hoàn toàn công cụ nào. Một hệ thống có thể dùng stored procedure cho nghiệp vụ và dbt cho analytical models.

4. Lab SQL: nhìn thấy lỗi trước khi học công cụ

Phần này chạy trên PostgreSQL hiện có bằng psql, DBeaver hoặc pgAdmin. Nếu chưa có PostgreSQL, đọc hiểu ví dụ trước rồi thực hành sau khi dựng môi trường bài 2. Các bảng tạm chỉ tồn tại trong phiên kết nối hiện tại; chạy toàn bộ lab trên cùng một connection. Bài 1 dùng bộ dữ liệu rút gọn, bài 2 sẽ tạo project bán hàng đầy đủ.

create temporary table raw_orders_demo (
    order_id integer,
    order_date date,
    status text,
    amount_vnd numeric(14,0)
);

insert into raw_orders_demo values
(101, '2026-01-01', ' PAID ', 250000),
(102, '2026-01-01', 'cancelled', 180000),
(103, '2026-01-02', 'paid', 320000),
(104, '2026-01-02', 'pending', 90000);

Cột status cố ý có chữ hoa và khoảng trắng. Nếu so sánh trực tiếp status = paid, đơn 101 sẽ bị bỏ sót. Nếu cộng toàn bộ amount, các đơn cancelled và pending lại lọt vào báo cáo. Hai câu SQL đều hợp lệ về cú pháp nhưng trả lời khác câu hỏi đã thống nhất.

select sum(amount_vnd) as all_order_value_vnd
from raw_orders_demo;

select sum(amount_vnd) as paid_without_normalizing_vnd
from raw_orders_demo
where status = 'paid';
Cách tínhKết quả mong đợiVì sao chưa đúng
Cộng mọi đơn840.000 VNDBao gồm hủy và chờ
Lọc status = 'paid' trực tiếp320.000 VNDBỏ sót chuỗi có khoảng trắng và chữ hoa

4.1. Chuẩn hóa riêng trước khi tổng hợp

with staging as (
    select
        order_id,
        order_date,
        lower(trim(status)) as order_status,
        amount_vnd
    from raw_orders_demo
),
paid_orders as (
    select *
    from staging
    where order_status = 'paid'
)
select
    order_date,
    count(*) as paid_order_count,
    sum(amount_vnd) as paid_revenue_vnd
from paid_orders
group by order_date
order by order_date;

staging đổi status về một biểu diễn nhất quán. paid_orders thể hiện quy tắc chọn đơn. SELECT cuối làm nhiệm vụ tổng hợp theo ngày. CTE không tự tạo ba bảng vật lý; trong câu SQL này chúng là các bước logic giúp bạn đọc và kiểm tra dễ hơn. Khi project lớn lên, ta có thể tách một số bước thành dbt model để tái sử dụng.

NgàySố đơn paidDoanh thu paid
2026-01-011250.000 VND
2026-01-021320.000 VND
Tổng2570.000 VND

Đọc kết quả bằng tay: ngày 1 chỉ có đơn 101 hợp lệ; ngày 2 chỉ có đơn 103. Tổng 570.000 là mốc đối chiếu của lab rút gọn. Quy trình review tốt bắt đầu từ vài dòng có thể tính tay trước khi tin một bảng hàng triệu dòng.

5. Từ câu SELECT tới dbt model

Trong project dbt, file stg_orders.sql có thể chứa bước chuẩn hóa; model doanh thu dùng ref để tham chiếu bước đó. Các đoạn dưới minh họa hình dạng file, chưa phải project độc lập để chạy ngay. Bài 2 sẽ cung cấp Compose, profile, cấu hình và dữ liệu nguồn đầy đủ.

select
    order_id,
    order_date,
    lower(trim(status)) as order_status,
    amount_vnd
from {{ source('shop', 'orders') }}
select
    order_date,
    count(*) as paid_order_count,
    sum(amount_vnd) as paid_revenue_vnd
from {{ ref('stg_orders') }}
where order_status = 'paid'
group by order_date

Phần trong hai cặp ngoặc nhọn là biểu thức Jinja được dbt xử lý trước khi SQL gửi tới database. source xác định một relation nguồn đã khai báo; ref xác định model khác và ghi nhận dependency. PostgreSQL không hiểu nguyên văn những biểu thức đó. Vì vậy, dán SQL model chưa compile vào cửa sổ SQL sẽ gây lỗi gần ký tự ngoặc nhọn.

Nếu model được cấu hình view, database giữ định nghĩa truy vấn và tính khi đọc. Nếu là table, kết quả được vật lý hóa tại lần build và chỉ thay đổi khi được xây lại hoặc cơ chế khác cập nhật. Lựa chọn này ảnh hưởng thời gian chạy, độ mới dữ liệu và chi phí. Bắt đầu bằng mô hình đơn giản, rồi đo trước khi tối ưu.

6. Kiểm chứng: chạy thành công chưa có nghĩa dữ liệu đúng

Kiểm tra dữ liệu cần bám vào quy tắc nghiệp vụ và các trường hợp có thể tính tay.
Kiểm tra dữ liệu cần bám vào quy tắc nghiệp vụ và các trường hợp có thể tính tay.

Một test phổ biến kiểm tra khóa không null, không trùng hoặc cột có giá trị thuộc tập cho phép. Nhưng nếu cả nhóm thống nhất nhầm doanh thu gồm đơn pending, mọi test kỹ thuật vẫn có thể pass. Cần thêm đối soát nghiệp vụ: số đơn hợp lệ, tổng tiền và chênh lệch với nguồn.

select order_id, count(*) as row_count
from raw_orders_demo
group by order_id
having count(*) > 1;

select *
from raw_orders_demo
where order_id is null or amount_vnd < 0;

Với dữ liệu ban đầu, hai truy vấn không trả dòng. Đó là kết quả mong đợi, không phải lỗi hiển thị. Một truy vấn phát hiện vi phạm thường trả các dòng sai, chứ không phải trả một số true. Sau đó, thử thêm một đơn có order_id=101: truy vấn đầu phải tìm được khóa trùng. Nếu test không phản ứng với dữ liệu lỗi cố ý, hãy xem lại test thay vì vội tin nó.

Chống trùng ở tầng phân tích khác chống trùng ở hệ thống giao dịch. Không nên dùng DISTINCT cho mọi bảng để làm đẹp số dòng: nó có thể che lỗi ingestion và bỏ mất khác biệt quan trọng. Cần xác định grain, nguồn ưu tiên và quy tắc chọn bản ghi mới nhất nếu nguồn có lịch sử cập nhật. Các bài sau sẽ thực hành từng phần.

7. Khi nào nên đưa dbt vào dự án?

dbt đáng cân nhắc khi nhiều báo cáo dùng lại cùng logic, model phụ thuộc nhau, nhiều người sửa SQL và cần review thay đổi có kiểm tra tự động. Một project vài bảng có thể bắt đầu nhỏ, không cần tạo hàng chục folder và macro ngay. Độ phức tạp cần được giải quyết bằng cấu trúc đủ dùng, không phải thêm tầng chỉ để giống một sơ đồ trên mạng.

Nếu chỉ truy vấn ad hoc một lần, chưa có dữ liệu trong warehouse hoặc phần lớn công việc là gọi API và xử lý file, việc cài dbt có thể chưa giải quyết nút thắt chính. Hãy làm rõ ingestion và môi trường dữ liệu trước. Nếu yêu cầu độ trễ vài mili giây cho sự kiện giao dịch, SQL batch model cũng không tự trở thành stream processor.

8. Bài tập tự kiểm tra

Thử đổi đơn 104 từ pending thành paid rồi chạy lại câu tổng hợp. Kết quả ngày 2 phải tăng từ 320.000 lên 410.000 VND; tổng hai ngày là 660.000 VND. Tiếp theo, đổi chuỗi trạng thái thành nhiều khoảng trắng và chữ hoa để xác nhận bước trim/lower còn hoạt động.

Trả lời ba câu trước khi sang bài 2: ai thực thi phép GROUP BY trong SQL model? PostgreSQL. dbt có tự biết đơn cancelled phải loại khỏi doanh thu không? Không, đó là quy tắc bạn phải khai báo. Chạy dbt Core CLI có tự tạo lịch hằng ngày không? Không, cần cơ chế gọi lệnh theo lịch hoặc nền tảng điều phối phù hợp.

Sau bài này, kết quả quan trọng nhất là phân biệt câu SQL đúng cú pháp với mô hình dữ liệu có định nghĩa đúng, có khả năng lặp lại và kiểm chứng. Bài 2 sẽ biến cách làm đó thành project retail_analytics chạy trên PostgreSQL local, dùng cùng dữ liệu cho các bài 3–5.

Tài liệu tham khảo

Scroll to Top