打卡报告的SQL查询

时间:2012-06-25 09:23:05

标签: sql sql-server sql-server-2008

我想在下表中的csv文件中生成报告。

   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 Query发帖。

4 个答案:

答案 0 :(得分:1)

在SQL中执行逻辑不是更容易吗?

按PAYCODE和OFFICEPUNCH分组(也可以通过截断时间的OFFICEPUNCH分组),然后你可以为Time In和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++;
}

答案 1 :(得分:0)

在Sql中执行min / max和分组可能会更容易。

但是,如果你在代码中完成它的销售,我会做这样的事情:

创建一个方法以将数据作为可枚举的行返回:

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执行一个带有min和max的漂亮组。您应该能够从此处开始进行其余的格式化和操作:

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
  }
}

我希望这能指导你朝着正确的方向前进。基本上剩下的就是将日期格式化为时间并计算小时数。

答案 2 :(得分: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;

答案 3 :(得分: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