T SQL查询格式以建立动态表

时间:2018-10-05 19:47:28

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

我需要帮助来创建查询以生成所需的结果。

我正在创建一个基于现有数据库表来跟踪员工出勤的应用程序。用户从日历中选择一个日期或一组日期(例如10/1/1810/2/1810/3/18)。他们单击提交,然后我需要生成一个表,该表显示每个员工在日期列中是否带有复选标记的日期。

该表称为“历史记录”,具有2个主要列:EmployeeID;和TransactionDate。每次员工走过一扇门(包括入口)时,都会创建一个历史交易记录(NFC徽章),该交易会添加一个新行,带有员工的ID和日期/时间戳。每个员工每天可能有几次刷卡,但我真正需要知道的是当天是否有一次刷卡。我正在发布有关表的外观以及查询结果以及表的外观的图片...

表格enter image description here

结果: enter image description here

我可以执行以下查询:

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

并以编程方式对其进行排序,但是我觉得有一种更有效的方法来查询我想要的结果。

任何帮助将不胜感激。让我知道是否需要进一步说明。

5 个答案:

答案 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

结果是....

enter image description here

不是最快或最高效的代码,但肯定很有趣。而且,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;