Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cara mengembalikan baris yang hilang dari tabel - Laporan Absen Karyawan

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)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menambah tanggal interval di Mysql

  2. Bagaimana cara mentranspos baris ke kolom dengan data dalam jumlah besar di BigQuery/SQL?

  3. Pilih produk dengan beberapa atribut, menggunakan AND sebagai gantinya ATAU concatenator, Model data EAV

  4. Tabel bernama 'suka' di MySQL

  5. Menggunakan IS NULL dan COALESCE di OrderBy Doctrine Querybuilder