我想在下表中的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发帖。
答案 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