2012-12-24 72 views
-2

我有兩個表,就像這樣:如何返回從表中「失蹤」行 - 員工缺席報告

master 
--------- 
empcode INT PRIMARY KEY 
name  VARCHAR 
dept  VARCHAR 

emp_tx 
---------- 
empcode INT  references MASTER(empcode) 
s_date  DATETIME 

emp_tx表記錄員工「in」和「出」的交易。當「中」或「出」事件發生的柱s_date存儲時間(作爲DATETIME值)。該交易與辦公區(通過指紋生物識別系統)記錄

實例數據從emp_tX表:

empcode s_datetime 
    ------- ------------------  
    1110  2012-12-12 09:31:42 (employee in time to the office) 
    1110  2012-12-12 13:34:17 (employee out time for lunch) 
    1110  2012-12-12 14:00:17 (employee in time after lunch) 
    1110  2012-12-12 18:00:12 (employee out time after working hours) 
    1112 
    etc. 

注: 如果員工是在辦公室缺席給定日期,那麼沒有行將被插入該日期的emp_tx交易表中。在給定日期沒有僱員時,該僱員和那個日期會有一行「缺失」。

誰能幫助我得到一個返回員工缺席,以產生一個員工缺席報告日期的SQL查詢?

輸入到查詢將是兩個日期值,一個「來自」日期和a「到」日期,指定日期範圍。查詢應返回的「缺位」所有出現(或不出現,而,非,如果沒有行的EMP_TX表中找到一個empcode任何日期「從」和「到」日期之間。

預期輸出:

如果我們輸入'2012-12-12'作爲「from」日期,'2012-12-20'作爲「to」日期,則查詢應該返回如下所示的行:

Empcode EmpName Department AbsentDate TotalNoofAbsent days 
------- ------- ---------- ----------- -------------------- 
1110  ABC  Accounts 2012-12-12 
1110  ABC  Accounts 2012-12-14      2 
1112  xyz  Software 2012-12-19 
1112  xyz  Software 2012-12-17      2 

我已經試過此查詢,我相信它沒有返回我想要的行:

select tx.date from Emp_TX as tx where Date(S_Date) not between '2012-12-23' and '2012-12-30' 

感謝。

+0

讓我成爲第一個和疑惑,最後問*你嘗試過什麼* –

+0

什麼是你的目標?不能不保留問題 –

+0

你嘗試過什麼嗎?如果是的話,請在這裏發佈你的SQL查詢,專家將幫助你糾正查詢。 –

回答

2

如果「缺席」被定義爲emp_tx表中的一行中不出現特定empcode特定日期(日期=從午夜到午夜24小時期間),並且...

如果在該日期的emp_tx表中沒有任何交易(即,當所有empcode在該日期不存在時沒有顯示「不存在」日期),然後...

你可以得到這樣的查詢設置的指定結果的前四列:(未經測試)

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 

獲得在同一結果集返回列第五TotalNoofAbsent是可能的,但它是會使這個查詢非常混亂。在處理返回的結果集時,可能會在客戶端更有效地處理此詳細信息。


如何查詢工作

別名爲d的內嵌視圖得到我們的一組我們正在檢查「日期」值。使用emp_tx表作爲這些「日期」值的來源是實現此目的的一種便捷方式。不是DATE()函數僅返回DATETIME參數的「日期」部分;我們使用GROUP BY來獲取不同的日期列表(即沒有重複值)。 (我們之後使用這種內聯視圖查詢,是作爲參數傳入的兩個值之間的一組不同的DATE值,還有其他更多參與的生成DATE值列表的方法。)

只要您認爲「缺席」的每個「日期」值都出現在表格的某處(也就是說,至少有一個empcode每個日期有一個感興趣的交易),並且只要行數在emp_tx表中不會過多,那麼內聯視圖查詢將工作得很好。

(注:行內視圖的查詢可以單獨運行,以驗證結果是正確的,因爲我們預期。)

下一步要做採取從內嵌視圖的結果,並執行一個CROSS JOIN操作(以生成笛卡爾積)以匹配每個empcode與從內聯視圖返回的每個date。這個操作的結果代表了每個可能發生的「出勤」。

查詢的最後一步是使用LEFT JOINWHERE IS NULL謂詞執行「反連接」操作。 LEFT JOIN(外連接)返回每個可能的出席事件(從左側開始),包括emp_tx表中沒有匹配行(出勤記錄)的出勤事件。

「訣竅」是包含一個謂詞(在WHERE子句中),它放棄找到匹配出勤記錄的所有行,以便我們留下的所有組合都是empcodedate(可能出席發生)沒有匹配出席交易的地方。 (注:我有意在謂詞中保留對s_date(DATETIME)列的引用「bare」,並使用範圍謂詞,這將使MySQL有效地使用包含該列的適當索引。 )

如果我們要將列引用包含在謂詞中的某個函數內,例如DATE(p.s_date),那麼MySQL將無法有效使用s_date列中的索引。


正如註釋(你的問題)中的一個所指出的,我們沒有做,標誌着僱員無論是作爲「進來」或「走出去」的交易之間沒有任何區別。我們只在給定的24小時「午夜至午夜」期間查找該empcode的交易。


還有其他的方法來得到同樣的結果集,但「反連接」模式通常證明給大集最佳的性能。

爲了獲得最佳性能,你可能會希望覆蓋索引:

... ON master (empcode, name, dept) 

... ON emp_tx (s_date, empcode) 
0

不幸的是,你的查詢會得到你一噸的結果......它總是返回所有日期爲您提供的範圍之外的僱員。你想檢查不存在你的日期之間的記錄。

它可能會爲此在純SQL ......我不能想辦法副手,而無需使用遊標什麼的DB-具體。這個Java僞代碼會給你1個員工的缺勤:

List<Date> findAbsences(int empCode, Date inDate, Date outDate) { 

    List<Date> result = new LinkedList<Date>(); 

    Calendar c = new Calendar(); 
    c.setTime(new Date(2012,12,12)); 

    while (!c.getTime().after(outDate)) { 
     // run query for EMP_TX records between inDate & outDate 
     //SELECT 1 FROM EMP_TX WHERE EmpCode = :empid AND S_Date BETWEEN :in AND :out; 

     if (!query.hasNext()) { 
      result.add(c.getTime); 
     } 

     c.add(Calendar.DATE, 1); 
    } 


} 
相關問題