Jika "ketidakhadiran" didefinisikan sebagai tidak munculnya baris dalam emp_tx
tabel untuk empcode
particular tertentu untuk tanggal tertentu (tanggal=tengah malam hingga tengah malam periode 24 jam), dan ...
Jika dapat diterima untuk tidak menunjukkan "ketidakhadiran" untuk tanggal ketika TIDAK ada transaksi di emp_tx
tabel untuk tanggal tersebut (yaitu, mengecualikan tanggal ketika SEMUA empcode tidak ada pada tanggal tersebut), lalu ...
Anda bisa mendapatkan empat kolom pertama dari kumpulan hasil yang ditentukan dengan kueri seperti ini:(belum diuji)
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
Mendapatkan kolom kelima TotalNoofAbsent
dikembalikan dalam hasil yang sama dimungkinkan, tetapi itu akan membuat kueri itu benar-benar berantakan. Detail ini mungkin lebih efisien ditangani di sisi klien, saat memproses hasil yang dikembalikan.
Cara kerja kueri
Tampilan sebaris alias sebagai d
memberi kami satu set nilai "tanggal" yang kami periksa. Menggunakan emp_tx
tabel sebagai sumber nilai "tanggal" ini adalah cara mudah untuk melakukan ini. Bukan DATE()
fungsi mengembalikan hanya bagian "tanggal" dari argumen DATETIME; kami menggunakan GROUP BY
untuk mendapatkan daftar tanggal yang berbeda (yaitu tidak ada nilai duplikat). (Apa yang kami cari, dengan kueri tampilan sebaris ini, adalah kumpulan nilai DATE yang berbeda antara dua nilai yang diteruskan sebagai argumen. Ada cara lain yang lebih terlibat, untuk menghasilkan daftar nilai DATE.)
Selama setiap nilai "tanggal" yang akan Anda anggap sebagai "ketidakhadiran" muncul di suatu tempat dalam tabel (yaitu, setidaknya satu empcode
memiliki satu transaksi pada setiap tanggal yang menarik), dan selama jumlah baris di emp_tx
tabel tidak berlebihan, maka kueri tampilan sebaris akan bekerja dengan cukup baik.
(CATATAN:Kueri dalam tampilan sebaris dapat dijalankan secara terpisah, untuk memverifikasi bahwa hasilnya benar dan seperti yang kita harapkan.)
Langkah selanjutnya adalah melakukan pengambilan hasil dari tampilan inline dan melakukan CROSS JOIN
operasi (untuk menghasilkan produk Cartesian) untuk mencocokkan SETIAP empcode
dengan SETIAP date
dikembalikan dari tampilan sebaris. Hasil dari operasi ini mewakili setiap kemungkinan terjadinya "kehadiran".
Langkah terakhir dalam kueri adalah melakukan operasi "anti-gabung", menggunakan LEFT JOIN
dan WHERE IS NULL
predikat. LEFT JOIN
(gabungan luar) mengembalikan setiap kemungkinan kehadiran kehadiran (dari sisi kiri), TERMASUK mereka yang tidak memiliki baris yang cocok (catatan kehadiran) dari emp_tx
tabel.
"Triknya" adalah memasukkan predikat (dalam klausa WHERE) yang membuang semua baris tempat ditemukannya catatan kehadiran yang cocok, sehingga yang tersisa hanyalah kombinasi empcode
dan date
(kemungkinan kemunculan kehadiran) di mana tidak ada transaksi kehadiran yang TIDAK SAMA.
(CATATAN:Saya sengaja meninggalkan referensi ke kolom s_date (DATETIME) "telanjang" di predikat, dan menggunakan predikat rentang. Ini akan memungkinkan MySQL untuk menggunakan indeks yang sesuai yang mencakup kolom itu secara efektif.)
Jika kita membungkus referensi kolom dalam predikat di dalam suatu fungsi mis. DATE(p.s_date)
, maka MySQL tidak akan dapat menggunakan indeks secara efektif pada s_date
kolom.
Seperti yang ditunjukkan oleh salah satu komentar (pada pertanyaan Anda), kami tidak membuat perbedaan antara transaksi yang menandai seorang karyawan sebagai "masuk" atau "keluar". Kami HANYA mencari keberadaan transaksi untuk empcode itu dalam periode "tengah malam hingga tengah malam" 24 jam.
Ada pendekatan lain untuk mendapatkan kumpulan hasil yang sama, tetapi pola "anti-gabung" biasanya memberikan performa terbaik dengan kumpulan besar.
Untuk kinerja terbaik, Anda mungkin ingin mencakup indeks:
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)