2012-06-25 73 views
-1

我想從下表中的csv文件中生成報表。針對打卡報表的SQL查詢

CARDNO  |  PAYCODE   |    OFFICEPUNCH 
    00001210  |  1210   |   6/22/2012 9:49:00 AM  
    00001210  |  1210   |   6/22/2012 7:58:00 PM  
    00001211  |  1211   |   6/23/2012 9:31:00 AM  
    00001211  |  1211   |   6/23/2012 6:12:00 PM 

它擁有員工衝數據,在一排每卡衝店,所以如果用戶的員工在早上打孔其卡將被標記爲在時間,但在同日的最後一拳將考慮爲外出時間,有時候員工在那裏打卡多次。所以我需要第一次和最後一次衝球時間。

問題

我想在下面的格式獲得CSV

Date  | PayCode | Card No | Intime | Outtime | Hrs Works 
2012-06-22 | 1210 | 00001210 | 9:30 | 18:00 | 7.3 
2012-06-22 | 1211 | 00001211 | 9:30 | 18:00 | 7.3 
2012-06-23 | 1210 | 00001210 | 9:30 | 18:00 | 7.3 
2012-06-23 | 1211 | 00001211 | 9:30 | 18:00 | 7.3 
2012-06-24 | 1210 | 00001210 | 9:30 | 18:00 | 7.3 
2012-06-24 | 1211 | 00001211 | 9:30 | 18:00 | 7.3 
                   ... and continue 

請幫助我,我怎麼能得到上述結果,我已經通過代碼嘗試,但我可以;噸實現它。

請使用sql查詢。

+1

你寫的標題到StreamWriter的,但你從來不寫實際行。你在問如何使用Streamwriter? –

+0

我想做循環中的邏輯部分,所以我可以得到以上格式的csv – Saqueib

回答

1

在SQL中執行邏輯不是更容易嗎?

集團通過PAYCODE和OFFICEPUNCH(也許用的時間截斷OFFICEPUNCH),那麼你可以做針對超時時間和MAX(OFFICEPUNCH)一個MIN(OFFICEPUNCH)。

編輯

SQL例如:

SELECT DISTINCT 
    CONVERT(VARCHAR(10), OFFICEPUNCH, 20) AS 'PunchDate' 
INTO 
    #Date 
FROM 
    MachineRawPunch 
WHERE 
    OFFICEPUNCH >= @p_StartDate 
AND 
    OFFICEPUNCH <= @p_EndDate 

SELECT 
    #Date.PunchDate AS 'Date', 
    TblEmployee.PAYCODE, 
    TblEmployee.PRESENTCARDNO AS 'CardNo', 
    MIN(CASE MachineRawPunch.ISMANUAL WHEN 'Y' THEN MachineRawPunch.OFFICEPUNCH ELSE CAST(#Date.PunchDate + ' 9:30' AS datetime) END) AS 'TimeIn', 
    CASE WHEN MachineRawPunch.ISMANUAL = 'N' THEN CAST(#Date.PunchDate + ' 18:00' AS datetime) 
     WHEN MAX(MachineRawPunch.OFFICEPUNCH) > MIN(MachineRawPunch.OFFICEPUNCH) 
     THEN MAX(MachineRawPunch.OFFICEPUNCH) 
     ELSE NULL END AS 'TimeOut' 
FROM 
    #Date 
CROSS JOIN 
    TblEmployee 
LEFT JOIN 
    MachineRawPunch 
ON 
    MachineRawPunch.PAYCODE = TblEmployee.PAYCODE 
AND 
    CONVERT(VARCHAR(10), MachineRawPunch.OFFICEPUNCH, 20) = #Date.PunchDate 
GROUP BY 
    #Date.PunchDate, 
    TblEmployee.PAYCODE, 
    TblEmployee.PRESENTCARDNO 
ORDER BY 
    #Date.PunchDate, 
    TblEmployee.PAYCODE, 
    TblEmployee.PRESENTCARDNO 

DROP TABLE #Date 

while (sqlReader.Read()) 
{ 
    // get the results of each column 
    string date = (string)sqlReader["Date"]; 
    string cardNumber = sqlReader["CARDNO"] == DBNull.Value ? string.Empty : (string)sqlReader["CARDNO"]; 
    DateTime inTime = sqlReader["TimeIn"] == DBNull.Value ? DateTime.MinValue : (DateTime)sqlReader["TimeIn"]; 
    DateTime outTime = sqlReader["TimeOut"] == DBNull.Value ? DateTime.MinValue : (DateTime)sqlReader["TimeOut"]; 
    string payCode = (string)sqlReader["PAYCODE"]; 

    //Stores single row as string 
    int hrsWorked = outTime == DateTime.MinValue ? 0 : outTime.Subtract(inTime).Hours; 
    int minsWorked = outTime == DateTime.MinValue ? 0 : outTime.Subtract(inTime).Minutes; 
    strRow = date + "," + 
      payCode + "," + 
      cardNumber + "," + 
      (inTime == DateTime.MinValue ? string.Empty : inTime.ToString("H:mm")) + "," + 
      (outTime == DateTime.MinValue ? string.Empty : outTime.ToString("H:mm")) + ", " + 
      hrsWorked + "." + minsWorked + " , Staus"; 
    Console.WriteLine(strRow); 
    //Write to file 
    // sw.WriteLine(strRow); 
    i++; 
} 
+0

如果有人可以提供SQL查詢字符串,這將是非常有益的。我卡在這裏PLZ幫我 – Saqueib

+0

請看我的更新。您也可以先將這兩個日期之間的行放在#表中,然後在該子集上執行此邏輯,但在存儲過程而不是內聯SQL中執行此操作可能也是一個好主意 - 爲了將來的可讀性和可維護性。 – Veldmuis

+0

感謝Veldmuis,查詢工作正常,只有一件事,如果有人缺席,它如何可以在PAYCODE前顯示null,目前缺席的記錄沒有列出。我已經將僱員數據存儲在其他表中的TblEmployee中,並參考PAYCODE – Saqueib

0

它可能會更容易做到最小/最大和SQL分組。

但是爲了以防萬一你賣了得到它的代碼做我會做這樣的事情:

創建來回報您的數據作爲枚舉行的方法:

public IEnumerable<IDataRecord> ExecuteSelect() 
{ 
    cmd = new SqlCommand(); 
    cmd.Connection = con; 
    cmd.CommandText = "SELECT CARDNO, OFFICEPUNCH, PAYCODE FROM MachineRawPunch WHERE OFFICEPUNCH >= @p_StartDate AND OFFICEPUNCH <= @p_EndDate ORDER BY PAYCODE, OFFICEPUNCH"; 
    cmd.Parameters.Add("@p_StartDate", SqlDbType.DateTime).Value = startDate.Date; 
    cmd.Parameters.Add("@p_EndDate", SqlDbType.DateTime).Value = endDate.Date.AddDays(1); 

    using (var reader = cmd.ExecuteReader()) 
    { 
    while (reader.Read()) yield return reader; 
    } 
} 

然後在您的導出按鈕點擊事件使用linq做最小和最大的漂亮組。您應該可以從此處完成格式化和操作的其餘部分:

private void buttonExport_Click(object sender, EventArgs e) 
{ 
    //Selects the rows into a list of typed objects. Easier for querying below: 
    var rows = 
    ExecuteSelect().Select(
     r => 
     new 
     { 
      CardNo = (string) r["CARDNO"], 
      OfficePunch = (DateTime) r["OFFICEPUNCH"], 
      PayCode = (string) r["PAYCODE"] 
     }).ToList(); 

    var groupedRows = (from r in rows 
        group r by new {r.CardNo, r.OfficePunch} 
        into g 
        select new 
           { 
           CardNo = g.Select(f => f.CardNo).FirstOrDefault(), 
           PayCode = g.Select(f => f.PayCode).FirstOrDefault(), 
           InDateTime = g.Min(min => min.OfficePunch), 
           OutDateTime = g.Max(max => max.OfficePunch) 
           }).ToList(); 

    foreach (var row in groupedRows) 
    { 
    //write to CSV 
    //row.CardNo, row.PayCode, row.InDateTime, row.OutDateTime 
    } 
} 

我希望這會引導您朝着正確的方向前進。基本上剩下的就是將日期格式化爲時間並計算小時數。

+0

感謝您的代碼,但它不斷循環使用此代碼。 string resRow =「」; 的foreach(在groupedRows VAR行) { //寫入CSV //row.CardNo,row.PayCode,row.InDateTime,row.OutDateTime resRow + = row.InDateTime.ToString(「YYYY-MM -dd「)+」,「+ row.CardNo +」,「+ row.PayCode +」,「+ row.InDateTime.ToString(」HH:MM「)+」,「+ row.OutDateTime.ToString(」HH :MM「)+」\ r \ n「; Console.WriteLine(resRow); } //啓用按鈕 – Saqueib

+0

SQL查詢將非常棒,請幫助我們 – Saqueib

+0

分組行的行數是多少? –

0

單查詢是不夠的:

select 
    PAYCODE, CARDNO, 
    min(officepunch) as INtime, 
    max(officepunch) as OutTime, 
    timediff(max(officepunch),min(officepunch)) as HRSWork 
FROM database.tablename 
group by CARDNO, PAYCODE, cast(officepunch as date) 
order by cardno; 
0
select * 
,  datediff(minute, first_in, last_out) as duration 
from (
     select emp_reader_id 
     ,  min(case when Event_entry.event_entry_name = 'IN' then trnevents.DT end) as first_in 
     ,  max(case when Event_entry.event_entry_name = 'OUT' then trnevents.DT end) as last_out 
     ,  cast(min(trnevents.DT) as date) as date 
     from trnevents inner join Event_entry on trnevents.EventCatId=Event_entry.EventCatId 
     group by 
       emp_reader_id 
     ,  cast(trnevents.DT as date) 
     ) as SubQueriesMustBeNamed 
     select * from trnevents