Nếu "vắng mặt" được xác định là sự không xuất hiện của một hàng trong emp_tx
bảng cho một empcode
cụ thể cho một ngày cụ thể (date =nửa đêm đến nửa đêm trong khoảng thời gian 24 giờ) và ...
Nếu có thể chấp nhận được nếu không hiển thị "vắng mặt" cho một ngày KHÔNG có giao dịch nào trong emp_tx
bảng cho ngày đó (tức là loại trừ một ngày mà TẤT CẢ các mã trống vào ngày đó), sau đó ...
Bạn có thể lấy bốn cột đầu tiên của tập kết quả được chỉ định bằng một truy vấn như sau:(chưa được kiểm tra)
SELECT m.empcode AS `EmpCode`
, m.name AS `EmpName`
, m.dept AS `Department`
, d.dt AS `AbsentDate`
FROM ( SELECT DATE(t.s_date) AS dt
FROM emp_tx t
WHERE t.s_date >= '2012-12-12'
AND t.s_date < DATE_ADD( '2012-12-20' ,INTERVAL 1 DAY)
GROUP BY DATE(t.s_date)
ORDER BY DATE(t.s_date)
) d
CROSS
JOIN master m
LEFT
JOIN emp_tx p
ON p.s_date >= d.dt
AND p.s_date < d.dt + INTERVAL 1 DAY
AND p.empcode = m.empcode
WHERE p.empcode IS NULL
ORDER
BY m.empcode
, d.dt
Lấy cột thứ năm đó TotalNoofAbsent
được trả về trong cùng một tập kết quả là có thể, nhưng nó sẽ làm cho truy vấn đó thực sự lộn xộn. Chi tiết này có thể được xử lý hiệu quả hơn ở phía máy khách, khi xử lý tập kết quả trả về.
Cách hoạt động của truy vấn
Chế độ xem nội tuyến có bí danh là d
cung cấp cho chúng tôi một tập hợp các giá trị "ngày tháng" mà chúng tôi đang kiểm tra. Sử dụng emp_tx
bảng làm nguồn của các giá trị "ngày tháng" này là một cách thuận tiện để thực hiện việc này. Không phải là DATE()
hàm chỉ trả về phần "ngày tháng" của đối số DATETIME; chúng tôi đang sử dụng GROUP BY
để có được danh sách ngày tháng riêng biệt (tức là không có giá trị trùng lặp). (Những gì chúng tôi đang theo đuổi, với truy vấn chế độ xem nội tuyến này, là một tập hợp các giá trị DATE riêng biệt giữa hai giá trị được chuyển vào dưới dạng đối số. Có nhiều cách khác, liên quan hơn, để tạo danh sách các giá trị DATE.)
Miễn là mọi giá trị "ngày" mà bạn sẽ coi là "vắng mặt" xuất hiện ở đâu đó trong bảng (nghĩa là, ít nhất một empcode
có một giao dịch vào mỗi ngày được quan tâm) và miễn là số hàng trong emp_tx
bảng không quá mức, khi đó truy vấn chế độ xem nội tuyến sẽ hoạt động hợp lý.
(LƯU Ý:Truy vấn trong chế độ xem nội tuyến có thể được chạy riêng, để xác minh rằng kết quả là chính xác và như chúng tôi mong đợi.)
Bước tiếp theo là lấy kết quả từ chế độ xem nội tuyến và thực hiện CROSS JOIN
hoạt động (để tạo ra một sản phẩm Descartes) để khớp với MỌI empcode
với MỌI date
được trả về từ chế độ xem nội tuyến. Kết quả của thao tác này thể hiện mọi trường hợp "tham dự" có thể xảy ra.
Bước cuối cùng trong truy vấn là thực hiện thao tác "chống tham gia", sử dụng LEFT JOIN
và WHERE IS NULL
Thuộc tính. LEFT JOIN
(nối ngoài) trả về mọi lần xuất hiện tham dự có thể có (từ phía bên trái), BAO GỒM những trường hợp không có hàng phù hợp (bản ghi tham gia) từ emp_tx
bảng.
"Thủ thuật" là bao gồm một vị từ (trong mệnh đề WHERE) loại bỏ tất cả các hàng nơi tìm thấy bản ghi tham dự phù hợp, để những gì chúng ta còn lại là tất cả các kết hợp của empcode
và date
(các trường hợp tham dự có thể xảy ra) khi KHÔNG có giao dịch tham dự MATCHING.
(LƯU Ý:Tôi đã cố ý để các tham chiếu đến cột s_date (DATETIME) "trống" trong các vị từ và các vị từ phạm vi đã sử dụng. Điều này sẽ cho phép MySQL sử dụng hiệu quả một chỉ mục thích hợp bao gồm cột đó.)
Nếu chúng ta bọc các tham chiếu cột trong các vị từ bên trong một hàm, ví dụ:DATE(p.s_date)
, thì MySQL sẽ không thể sử dụng hiệu quả một chỉ mục trên s_date
cột.
Như một trong những nhận xét (về câu hỏi của bạn) đã chỉ ra, chúng tôi không phân biệt bất kỳ sự phân biệt nào giữa các giao dịch đánh dấu một nhân viên là "đến" hay "đi ra ngoài". Chúng tôi CHỈ tìm kiếm sự tồn tại của một giao dịch cho mã trống đó trong khoảng thời gian 24 giờ nhất định "từ nửa đêm đến nửa đêm".
Có những cách tiếp cận khác để có được cùng một tập hợp kết quả, nhưng kiểu "chống nối kết" thường mang lại hiệu suất tốt nhất với các tập hợp lớn.
Để có hiệu suất tốt nhất, bạn có thể muốn bao gồm các chỉ mục:
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)