Tách sự kiện khỏi bản chụp định kỳ
Giữ biến động kho riêng với số dư cuối ngày, kiểm tra kho thiếu bản chụp và đối soát trạng thái với thay đổi theo ranh giới báo cáo rõ ràng.

Biến động tồn kho ghi một thay đổi. Bản chụp tồn kho ghi số dư tại một ranh giới cụ thể. Cả hai đều có thể chứa kho, sản phẩm và số lượng, nhưng số lượng trả lời những câu hỏi khác nhau. Cộng ba số dư cuối ngày không cho biết có bao nhiêu đơn vị hàng cùng sẵn có tại một thời điểm; thiếu bản chụp cũng không có nghĩa kho đã hết hàng.
Với người phân tích hoặc kỹ sư đã biết tổng hợp SQL, đây là quyết định mô hình thực tế. Dùng sự kiện để nghiên cứu hoạt động trong một khoảng, dùng bản chụp để nghiên cứu trạng thái tại ranh giới. Ví dụ giữ hai quan sát riêng, kiểm tra độ phủ bản chụp và chỉ đối soát chúng khi nêu rõ giả định về nhật ký sự kiện cùng phạm vi đo.
Định nghĩa dòng sự kiện khác với dòng bản chụp
Doanh nghiệp giả lập có hai kho A và B, chứa cùng sản phẩm với cùng đơn vị vật lý. Một dòng biến động đại diện cho một thay đổi số lượng có dấu tại kho. Một dòng bản chụp đại diện cho số dư được đếm khi đóng ngày báo cáo UTC của kho ấy. Nguồn định nghĩa số dư đóng ngày là số dư sau mọi biến động thuộc ngày đó, ngay trước khi ngày tiếp theo bắt đầu.
Hướng dẫn bảng fact của Microsoft phân biệt fact giao dịch với bản chụp định kỳ và dùng số dư tồn kho hằng ngày làm ví dụ bản chụp. Điểm phân biệt hữu ích ở đây là quan sát, không phải có cột ngày hay không. Cả hai bảng có ngày; một bảng chứa thay đổi, bảng kia chứa trạng thái.
Dữ liệu có ba ngày báo cáo và tập hai kho cố định được khai báo độc lập. Số lượng và tổng trong ví dụ là số nguyên nhỏ. Khóa chính của bản chụp ngăn có hai số dư được chọn cho cùng kho và ngày, nhưng không buộc mọi số dư mong đợi phải tới nơi.
CREATE TEMP TABLE report_days (day TEXT PRIMARY KEY);
CREATE TEMP TABLE warehouses (warehouse TEXT PRIMARY KEY);
CREATE TEMP TABLE stock_snapshots (
day TEXT NOT NULL,
warehouse TEXT NOT NULL,
units INTEGER NOT NULL,
PRIMARY KEY (day, warehouse)
);
CREATE TEMP TABLE movements (
movement_id INTEGER PRIMARY KEY,
day TEXT NOT NULL,
warehouse TEXT NOT NULL,
delta_units INTEGER NOT NULL
);
INSERT INTO report_days VALUES ('2026-07-01'), ('2026-07-02'), ('2026-07-03');
INSERT INTO warehouses VALUES ('A'), ('B');
INSERT INTO stock_snapshots VALUES
('2026-07-01', 'A', 10), ('2026-07-01', 'B', 6),
('2026-07-02', 'A', 14), ('2026-07-02', 'B', 6),
('2026-07-03', 'A', 9);
INSERT INTO movements VALUES
(1, '2026-07-02', 'A', 4),
(2, '2026-07-03', 'A', -5),
(3, '2026-07-03', 'B', 2);
CREATE TEMP VIEW daily_stock AS
SELECT d.day, COUNT(*) AS expected_warehouses,
COUNT(s.warehouse) AS observed_warehouses,
CASE WHEN COUNT(s.warehouse) = COUNT(*) THEN SUM(s.units) END
AS network_units
FROM report_days d
CROSS JOIN warehouses w
LEFT JOIN stock_snapshots s ON s.day = d.day AND s.warehouse = w.warehouse
GROUP BY d.day;
SELECT * FROM daily_stock ORDER BY day;
Ngày đầu có hai kho mong đợi và hai kho được ghi nhận, tổng 16 đơn vị. Ngày thứ hai cũng phủ đủ, tổng 20. Ngày thứ ba mong đợi hai kho nhưng chỉ nhận một, nên network_units là null. Đã biết A có chín đơn vị; các quan sát này chưa xác lập số dư của toàn mạng kho.
Giữ thông tin thiếu độ phủ trong kết quả báo cáo
Chỉ cộng các bản chụp đã lưu sẽ báo chín cho ngày 3 tháng 7 và làm kho bị thiếu biến mất. Điền B bằng không lại khẳng định B đã được đếm và không còn hàng. Không kết luận nào suy ra từ một dòng chưa tới. Tập kho mong đợi phải đến từ hợp đồng báo cáo, không phải từ những dòng tình cờ có mặt.
Tập thực tế có thể đổi khi kho mở, đóng hoặc rời phạm vi báo cáo. Hãy mô hình hóa ngày đủ điều kiện và xây tập mong đợi cho từng ngày. Đừng suy ra kho đóng chỉ vì thiếu bản trích xuất. Ngược lại, không yêu cầu bản chụp trước khi kho thuộc phạm vi. Hai kho cố định là sự đơn giản hóa có chủ ý của ví dụ.
Tài liệu kiểm thử dữ liệu dbt mô tả các khẳng định về tính duy nhất, null và quan hệ. Khóa bản chụp duy nhất hữu ích, nhưng tính đầy đủ cần được kiểm bằng tập mong đợi. Kiểm tra quan hệ cũng nên từ chối bản chụp hoặc biến động của kho chưa khai báo, thay vì để chúng biến mất ngoài tập dẫn của báo cáo.
Đối soát tổng thay đổi với ranh giới số dư
Các dòng biến động mô tả hoạt động ngày 2 và 3 tháng 7. Thay đổi ròng là bốn trừ năm cộng hai, bằng một đơn vị:
SELECT day, SUM(delta_units) AS net_change
FROM movements
GROUP BY day
ORDER BY day;
SELECT SUM(delta_units) AS period_net_change
FROM movements
WHERE day >= '2026-07-02' AND day < '2026-07-04';
Thay đổi hằng ngày là cộng bốn và trừ ba; tổng kỳ là cộng một. Nếu nhật ký biến động đầy đủ, dùng cùng tập hàng vật lý và chứa mọi điều chỉnh giữa hai ranh giới đóng ngày, số dư 16 cuối ngày 1 tháng 7 dẫn tới số dư tái dựng 17 cuối ngày 3 tháng 7. Phương trình này là đối soát có điều kiện, không phải quan sát thay thế cho bản chụp B bị thiếu.
Với các giả định đó, A được tái dựng thành mười cộng bốn trừ năm, bằng chín. B thành sáu cộng hai, bằng tám. Điều này gợi ý cần điều tra gì khi thiếu số đếm cuối của B. Nó không chứng minh nhật ký đầy đủ chỉ vì phép tính cho số dư có vẻ hợp lý. Không có biến động B ngày 2 tháng 7 chỉ mang nghĩa thay đổi bằng không khi hợp đồng nhật ký đầy đủ được đáp ứng.
Để tiếp tục ví dụ, thêm bản chụp ngày 3 tháng 7 của B với tám đơn vị. Tổng cuối ngày quan sát được thành 17, khớp tổng tái dựng. Trên bản gốc mới, thêm bảy thay vì tám: tổng quan sát thành 16, để lại phần dư đối soát âm một. Hãy điều tra thời điểm, biến động thiếu, khác biệt phạm vi hoặc điều chỉnh sau kiểm đếm. Riêng phần dư không cho biết giải thích nào đúng.
Quyết định phép tổng hợp theo thời gian trả lời câu hỏi gì
Sau khi thêm số đếm tám của B, ba số dư cuối ngày là 16, 20 và 17. Tổng là 53. Đây là tổng của ba quan sát tồn kho, không phải 53 đơn vị hàng đồng thời sẵn có và cũng không phải chỉ số lượng hàng đi qua kho. Trung bình cộng là 53 chia ba, xấp xỉ 17,67 đơn vị, được hiểu cụ thể là trung bình của ba quan sát đóng ngày ấy.
Nó không phải tồn kho trung bình liên tục có trọng số theo thời gian trong kỳ. Các bản chụp không chứa thông tin về đỉnh tồn, thiếu hàng trong ngày hoặc thời lượng của những số dư trung gian. Doanh nghiệp có thể chọn trung bình tồn cuối ngày một cách hợp lý, nhưng tên chỉ số cần giữ quy ước lấy mẫu ấy.
Truy vấn sau chỉ công bố trung bình khi cả ba ngày mong đợi đều phủ đủ kho:
SELECT COUNT(*) AS expected_days,
SUM(observed_warehouses = expected_warehouses) AS complete_days,
CASE WHEN SUM(observed_warehouses = expected_warehouses) = COUNT(*)
THEN AVG(network_units) END AS mean_daily_closing_units
FROM daily_stock;
Trên dữ liệu gốc chưa đầy đủ, kết quả là ba ngày mong đợi, hai ngày đầy đủ và trung bình null. Sau khi thêm bản chụp tám đơn vị của B, kết quả là ba, ba và xấp xỉ 17,67. AVG đơn giản trên view gốc sẽ bỏ ngày null, trả 18 từ riêng 16 và 20. Tài liệu hàm tổng hợp PostgreSQL mô tả các hàm như AVG tính trên đầu vào không null; hành vi đó không phải chính sách xử lý ngày bị thiếu.
Cuối cùng, giữ nhất quán định nghĩa chuyển kho và quyền sở hữu hàng. Chuyển hàng có thể làm giảm một kho, tăng kho khác mà không đổi tồn toàn mạng, nhưng hàng đang vận chuyển cần có vị trí rõ trong tập đối tượng. Hai bản chụp dùng quy ước chốt khác nhau có thể đếm cùng hàng hai lần hoặc bỏ sót. Cùng mã sản phẩm và tổng khớp chưa đủ xác lập tính so sánh được về vật lý.
Hãy tạo lại dữ liệu gốc cho từng bài tập: thêm B bằng tám, thêm B bằng bảy và thử thêm bản chụp A trùng cho ngày 3 tháng 7. Kiểm tra riêng tổng quan sát, phần dư đối soát và lỗi khóa chính. Sau đó bỏ một biến động trong khi vẫn giữ đủ bản chụp, rồi giải thích vì sao kiểm tra độ phủ thành công nhưng đối soát thất bại. Hai bảng bổ sung cho nhau vì giữ bằng chứng khác nhau, không phải vì một bảng tự động thay thế được bảng kia.