我有一个包含日期,时间,员工ID和打卡类型(IN,OUT)的sql表,数据如下:
EMPID Date Time Punch type
123 2015-08-01 08:00 AM EMPIN
123 2015-08-01 01:00 PM EMPOUT
123 2015-08-01 02:30 PM EMPIN
123 2015-08-01 07:30 PM EMPOUT
123 2015-08-02 09:30 PM EMPIN
123 2015-08-02 11:00 AM EMPIN
123 2015-08-02 06:00 PM EMPOUT
123 2015-08-03 08:00 AM EMPIN
123 2015-08-03 06:00 PM EMPOUT
123 2015-08-03 02:30 AM EMPOUT
123 2015-08-04 08:00 AM EMPIN
123 2015-08-04 06:00 PM EMPOUT
我想在日期下显示打孔时间但没有数据透视表,因为我无法在类型时间上应用聚合函数,我已经尝试了数据透视但是它没有用。
我希望将它们显示为以下内容:
EMPID Punch type 2015-08-01 2015-08-02 2015-08-03 2015-08-04
123 EMPIN 08:00 AM 11:00 AM 08:00 AM 08:00 AM
123 EMPOUT 01:00 PM 06:00 PM 06:00 PM 06:00 PM
123 EMPIN 02:30 PM 09:30 PM
123 EMPOUT 07:30 PM 02:30 AM
,我的代码是:
DECLARE @StartDate DATETIME = '20150801'
,@EndDate DATETIME = '20150831'
if NOT EXISTS (
SELECT * FROM tempdb.dbo.sysobjects o
WHERE o.xtype IN ('U')
AND o.id = object_id(N'tempdb..#TABLE')
)
CREATE TABLE #TABLE (date DATETIME,numberOFWorkingHour INTEGER,empID NVARCHAR(6),time time,funckey NVARCHAR(20))
insert #TABLE
SELECT DISTINCT CONVERT(NVARCHAR(12),a.date) AS Date
,dbo.GetWorkingHourPerDay(a.date,a.empID) as numberOFWorkingHour
,a.EMPID
,a.time
,a.FuncKey
FROM
@EmployeesTable et
LEFT JOIN PERS_Attendance a ON a.empID = et.empid
LEFT JOIN PERS_EmployeeProfile EmpP ON EmpP.ID = a.EmpID
WHERE a.Date BETWEEN @StartDate AND @EndDate
GROUP BY a.empID,a.Date,a.time,a.FuncKey
--select * FROM #TABLE order by date
DECLARE @cols AS VARCHAR(MAX)
DECLARE @query AS VARCHAR(MAX)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(cast(CONVERT(VARCHAR(20), date,103 ) as varchar(10)))
FROM
(
SELECT a1.date FROM (
SELECT DISTINCT date
FROM #TABLE
WHERE Date BETWEEN @StartDate AND @EndDate
)a1
) t
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1,1,'')
SET @query =
' SELECT EMPID,funckey,' + @cols + '
FROM
(
SELECT t.EMPId,convert(varchar(20), t.date,103)date,t.time,t.funckey, t.numberOFWorkingHour
FROM #TABLE t
)src
pivot
(
AVG(time)
for date in (' + @cols + ')
) p WHERE 1=1'
EXEC(@Query)
if object_id('tempdb..#TABLE') IS NOT NULL
BEGIN
DROP TABLE #TABLE
END
正如我所提到的,时间类型不适用于枢轴,所以我应该用它替换它?
答案 0 :(得分:1)
此代码提供正确的输出:
create table #table(empid int, pdate date, ptime time, ptype varchar(10));
go
insert into #table(empid, pdate, ptime, ptype) values
(123, '2015-08-01', '08:00 AM', 'EMPIN')
, (123, '2015-08-01', '01:00 PM', 'EMPOUT')
, (123, '2015-08-01', '02:30 PM', 'EMPIN')
, (123, '2015-08-01', '07:30 PM', 'EMPOUT')
, (123, '2015-08-02', '09:30 PM', 'EMPIN')
, (123, '2015-08-02', '11:00 AM', 'EMPIN')
, (123, '2015-08-02', '06:00 PM', 'EMPOUT')
, (123, '2015-08-03', '08:00 AM', 'EMPIN')
, (123, '2015-08-03', '06:00 PM', 'EMPOUT')
, (123, '2015-08-03', '02:30 AM', 'EMPOUT')
, (123, '2015-08-04', '08:00 AM', 'EMPIN')
, (123, '2015-08-04', '06:00 PM', 'EMPOUT');
declare @cols nvarchar(max), @query nvarchar(max);
declare @StartDate date = '20150801', @EndDate date = '20150803'
declare @ParmDefinition nvarchar(200) = '@StartDate date, @EndDate date'
SELECT @cols = STUFF((
SELECT ', ' + QUOTENAME(CONVERT(NVARCHAR(20), pdate,102))
FROM (
SELECT DISTINCT pdate FROM #table
WHERE pDate BETWEEN @StartDate AND @EndDate
) t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
;
Select @cols
Set @query = '
With order_by_empid(empid, pdate, ptime, ptype, n) as (
Select empid, pdate, ptime, ptype
, n = ROW_NUMBER() over(partition by empid order by pdate, ptime)
From #table
WHERE pDate BETWEEN @StartDate AND @EndDate
), match_days(start, empid, pdate, ptime, ptype) as (
Select o1.pdate, o2.empid, o2.pdate, o2.ptime, o2.ptype From order_by_empid as o1
Inner Join order_by_empid as o2 on o1.n = o2.n-1
Where o1.ptype = ''EMPIN''
Union All
Select o1.pdate, o1.empid, o1.pdate, o1.ptime, o1.ptype From order_by_empid as o1
Where o1.ptype = ''EMPIN''
), data(empid, pdate, ptime, ptype, n) as(
Select g.empid, g.start, g.ptime, g.ptype
, n = ROW_NUMBER() over(partition by empid, start order by pdate, ptime)
From match_days as g
)
Select piv.empid, piv.ptype, '+@cols+'
From data as d
Pivot (
max(ptime)
for pdate in('+@cols+')
) as piv
order by piv.empid, piv.n;
';
exec sp_executesql @query, @ParmDefinition, @StartDate = @StartDate, @EndDate = @EndDate;
go
drop table #table
我使用了几个CTE来分解它。它更容易展示和解释它是如何工作的......
order_by_empid
按日期和时间为每个empid订购数据。match_days
用于将IN和OUT配对在一起,即使OUT有时在第二天。它为每个OUT线获得正确的IN日期。data
然后按正确的日期和时间对它们进行排序,然后可以使用Pivot来旋转它。输出:
empid | ptype | 2015-08-01 | 2015-08-02 | 2015-08-03 | 2015-08-04
123 | EMPIN | 14:30:00.0000000 | 21:30:00.0000000 | 08:00:00.0000000 | 08:00:00.0000000
123 | EMPOUT | 19:30:00.0000000 | 18:00:00.0000000 | 18:00:00.0000000 | 18:00:00.0000000