我需要帮助来创建查询以生成所需的结果。
我正在创建一个基于现有数据库表来跟踪员工出勤的应用程序。用户从日历中选择一个日期或一组日期(例如10/1/18
,10/2/18
和10/3/18
)。他们单击提交,然后我需要生成一个表,该表显示每个员工在日期列中是否带有复选标记的日期。
该表称为“历史记录”,具有2个主要列:EmployeeID;和TransactionDate。每次员工走过一扇门(包括入口)时,都会创建一个历史交易记录(NFC徽章),该交易会添加一个新行,带有员工的ID和日期/时间戳。每个员工每天可能有几次刷卡,但我真正需要知道的是当天是否有一次刷卡。我正在发布有关表的外观以及查询结果以及表的外观的图片...
我可以执行以下查询:
select employeeid, TranDate from History
where (CAST(trandate as DATE) = '2018-10-1' or CAST(trandate as DATE) = '2018-10-2' or CAST(trandate as DATE) = '2018-10-3' )
order by employeeid, TranDate
并以编程方式对其进行排序,但是我觉得有一种更有效的方法来查询我想要的结果。
任何帮助将不胜感激。让我知道是否需要进一步说明。
答案 0 :(得分:0)
您想要做的就是枢轴
尝试使用此代码
SELECT employeeid
,case when [2018-10-1] > 0 then '1' else '' end as [2018-10-1]
,case when [2018-10-2] > 0 then '1' else '' end as [2018-10-2]
,case when [2018-10-3] > 0 then '1' else '' end as [2018-10-3]
FROM(
SELECT employeeid
, TranDate
, 1 as num
FROM History
WHERE (CAST(trandate as DATE) = '2018-10-1'
or CAST(trandate as DATE) = '2018-10-2'
or CAST(trandate as DATE) = '2018-10-3' )
)
PIVOT(
COUNT(num)
FOR TranDate IN ([2018-10-1],[2018-10-2],[2018-10-3])
) as pvt
您可以在PIVOT, UNPIVOT SQL上查看PIVOT和UNPIVOT上的sql文档,此外,如果您想为transdate字段提供更多动态信息,可以查看Dynamic Pivot
答案 1 :(得分:0)
您说:“我真正需要的是知道当天是否有一次刷卡。”
答案-汇总查询
select employeeid, TranDate, count(TranDate) as count
from History
where -- look below
Group by employeeid, TranDate
要放在WHERE
中的内容是什么? - 要看。如果您要月期间,请
TranDate between '2018-10-1' and '2018-10-31 23:59:59.999'
如果要特定日期,请
CAST(trandate as DATE) in ('2018-10-1', '2018-10-11', '2018-10-11')
在后一种情况下,您将不得不动态地构建它
但是在这种情况下,您将面临一个新问题-如果您的人员从未进过门怎么办?该人员将不在列表中。然后,您需要letf join
并使用包含所有员工的表
现在 ,因为我不是TSql超级专家,但我喜欢编码,因此向您展示了有效代码可以通过编程方式完成。下面是几个可以合并为一个的代码段
-- SETUP
create table recs (id int, dt date );
insert into recs values(1, '2018-10-1');
insert into recs values(1, '2018-10-1');
insert into recs values(2, '2018-10-2');
insert into recs values(2, '2018-10-2');
insert into recs values(2, '2018-10-3');
insert into recs values(3, '2018-10-3');
insert into recs values(3, '2018-10-3');
insert into recs values(3, '2018-10-4');
insert into recs values(3, '2018-10-1');
-- Prepare Date Grid table
DECLARE crs_dt CURSOR FOR SELECT dt FROM recs group by dt order by dt;
declare @createTbl varchar(1200) = 'create table tbl (id int, ';
declare @fetched varchar(20);
OPEN crs_dt;
FETCH NEXT FROM crs_dt into @fetched;
WHILE @@FETCH_STATUS = 0
BEGIN
set @createTbl = @createTbl + '['+@fetched+'] int'
FETCH NEXT FROM crs_dt into @fetched;
if @@FETCH_STATUS = 0
begin set @createTbl = @createTbl + ','; end
END
set @createTbl = @createTbl + ')';
CLOSE crs_dt;
DEALLOCATE crs_dt;
select @createTbl; -- just a test
execute (@createTbl)
SELECT * FROM tbl; -- just a test
-- LOAD date grid table with data
DECLARE crs_rec CURSOR FOR
SELECT id, dt, FORMAT ( dt, 'yyyy-MM-dd' ) colName,
(case count(dt) when 0 then 0 else 1 end) cnt
FROM recs group by id, dt order by dt;
declare @createInsert varchar(1200);
declare @id int, @dt date, @colName varchar(20),@yesNo int;
OPEN crs_rec;
FETCH NEXT FROM crs_rec into @id, @dt, @colName, @yesNo;
WHILE @@FETCH_STATUS = 0
BEGIN
if exists(select 1 from tbl where id = @id)
set @createInsert = 'update tbl set ['+@colName+']='+cast(@yesNo as varchar(1))+ ' where id='+ cast(@id as varchar(1000));
else
set @createInsert =
'insert into tbl (id,['+@colName+']) values ('+cast(@id as varchar(1000))+','+cast(@yesNo as varchar(1))+')';
select @createInsert; -- just a test
execute (@createInsert);
FETCH NEXT FROM crs_rec into @id, @dt, @colName, @yesNo;
END
CLOSE crs_rec;
DEALLOCATE crs_rec;
commit;
-- Lets Load data
SELECT * FROM tbl
结果是....
不是最快或最高效的代码,但肯定很有趣。而且,1-这是完全动态的。 2-如果查看结果,现在回到我前面提到的问题,您可以将此表加入员工的完整列表,并获取整个数据集,包括在选定期间未刷卡的员工。
答案 2 :(得分:0)
因此,我想出了一种获得所需结果的方法。
首先,我需要获取不同的employeeID并将其存储到临时表中:
create table #TempTable
(
EmployeeID varchar(25)
)
insert into #TempTable (EmployeeID)
select distinct employeeID from History order by employeeID;
从这里,我可以将我的临时表加入到“历史记录”表中,并准确选择要查找的内容:
SELECT distinct M.EmployeeID AS Employee,
(SELECT CASE WHEN EXISTS
(SELECT 1 FROM HISTORY WHERE TAGID = M.EmployeeID AND (CAST(TRANDATE AS DATE) = '10/12/2018'))
THEN CAST (1 AS BIT) ELSE CAST (0 AS BIT) END) AS '10/12/2018'
FROM #TempTable AS M left JOIN HISTORY AS H ON M.EmployeeID = H.TAGID where m.EmployeeID = '000000000000000000000001' order BY Employee
最后删除临时表:
drop table #TempTable
对于更多日期,我只添加一个新列,将其日期作为标题。 感谢大家在此问题上的帮助。
答案 3 :(得分:0)
使用@TS创建表:
create table recs (id int, dt date );
insert into recs values(1, '2018-10-1');
insert into recs values(1, '2018-10-1');
insert into recs values(2, '2018-10-2');
insert into recs values(2, '2018-10-2');
insert into recs values(2, '2018-10-3');
insert into recs values(3, '2018-10-3');
insert into recs values(3, '2018-10-3');
insert into recs values(3, '2018-10-4');
insert into recs values(3, '2018-10-1');
declare @dts as varchar(max) =''
declare @dtsSelect as varchar(max) =''
select @dts = @dts + ',[' +dt +']',
@dtsSelect = @dtsSelect + ',Case WHEN [' +dt+']>0 then 1 else 0 end ['+dt+']'
From (select distinct cast(dt as varchar(100)) dt from recs) recs
//we use some variables to create columns should apear in pivot list and
// also to check if we have a value for column then put 1 instead
set @dts = Stuff(@dts,1,1,'')
set @dtsSelect = Stuff(@dtsSelect,1,1,'')
//delete the first comma
declare @sql nvarchar(max) = '
select id,'+@dtsSelect+' from recs
pivot(Count(dt) For dt in('+@dts+'))PV
'
exec sp_executesql @stme = @sql
假设日期并不总是相同
答案 4 :(得分:-1)
如果枢轴列固定,则可以使用此
编辑-我猜它也可以是动态的,因为您可以动态创建SQL语句。
Microsoft Docs : FROM - Using PIVOT and UNPIVOT
示例
select * from History
PIVOT
(
COUNT(TranDate)
FOR TranDate IN ([2018-10-01], [2018-10-02], [2018-10-03])
) AS PivotTable;