首先,我要感谢帮助这个复杂而困难的查询的朋友们。
我有三张桌子
表1
StaffId FirstName LastName staffType
---------------------------------------
1 Adam Sorme Student
2 Lara Sandra Teacher
3 Jack Jones Student
表2
GateId GateName
---------------------------------------
1 frontDoor
2 superDoor
表3
Id transitionDate GateId StaffId
---------------------------------------
1 2018-01-1 08:00:00 1 1
2 2018-01-1 10:00:00 2 1
3 2018-01-1 20:00:00 2 1
4 2018-01-2 07:00:00 1 2
5 2018-01-2 10:00:00 1 3
6 2018-01-9 12:00:00 2 2
我想要每天的学生的第一次和最后一次动作。如果指定日期之间没有可用的移动,则必须将值设置为null
transitionDate> '2018-01-1 00:00:00 000'
and transitionDate< '2018-01-03 00:00:00 000'
输出:
Id Date MinTransitionDate MaxTransitionDate FirstGateName LastGateName StaffId StaffType
1 2018-01-01 2018-01-1 08:00:00 2018-01-1 20:00:00 frontDoor superDoor 1 Student
2 2018-01-01 null null null null 3 student
3 2018-01-02 null null null null 1 student
4 2018-01-02 2018-01-2 10:00:00 null frontDoor null 3 student
以下查询部分有效。
select
q.*,
g1.GateName as first_gate_name,
g2.GateName as last_gate_name
from
(
select s.staffId, d.dte,
min(t.transitionDate) as min_Date,
max_Date= case when count(1)>1 then max(t.transitionDate) else null end,
max(case when seqnum_asc = 1 then gateId end) as first_gateid,
max(case when seqnum_desc = 1 then gateId end) as last_gateid
from (select s.* from Staff s where stafftype = 'Student') s cross join
(select distinct cast(transitionDate as date) as dte from Transitions) d left join
(select t.*,
row_number() over (partition by StaffId, cast(transitionDate as date) order by transitionDate) as seqnum_asc,
row_number() over (partition by StaffId, cast(transitionDate as date) order by transitionDate desc) as seqnum_desc
from Transitions t
) t
on cast(t.transitiondate as date) = d.dte and
t.staffId = s.staffId and
1 in (t.seqnum_asc, t.seqnum_desc)
group by s.staffId, d.dte
) q
left join Gates g1 on g1.gateId = q.first_gateid
left join Gates g2 on g2.gateId = q.last_gateid
问题:4.行中的max_date为空。我希望last_gateid的值为null。你能帮帮我吗?
答案 0 :(得分:2)
快速修复将取代此行
max(case when seqnum_desc = 1 then gateId end) as last_gateid
带
max(case when (seqnum_desc = 1 and seqnum_asc != 1) then t.gateId end) as last_gateid
答案 1 :(得分:2)
很明显,有人帮助你编写查询,你给了他更多的问题解释,我做的是调整你提供的查询,并使用相同的逻辑给你所需的输出,虽然我宁愿重写它以一种更容易理解的方式:
select
q.*,
g1.GateName as first_gate_name,
g2.GateName as last_gate_name
from
(
select s.staffId, d.dte,
min(t.transitionDate) as min_Date,
max_Date= case when count(1)>1 then max(t.transitionDate) else null end,
max(case when seqnum_asc = 1 then gateId end) as first_gateid,
case when count(1)>1 then MAX(gateId) end as last_gateid
from (select s.* from Staff s where stafftype = 'Student') s cross join
(select distinct cast(transitionDate as date) as dte from Transitions) d left join
(select t.*,
row_number() over (partition by StaffId, cast(transitionDate as date) order by transitionDate) as seqnum_asc,
row_number() over (partition by StaffId, cast(transitionDate as date) order by transitionDate desc) as seqnum_desc
from Transitions t
) t
on cast(t.transitiondate as date) = d.dte and
t.staffId = s.staffId and
1 in (t.seqnum_asc, t.seqnum_desc)
group by s.staffId, d.dte
) q
left join Gates g1 on g1.gateId = q.first_gateid
left join Gates g2 on g2.gateId = q.last_gateid
答案 2 :(得分:1)
IF OBJECT_ID('dbo.Staff') IS NOT NULL DROP TABLE Staff
create table Staff (StaffId int, FirstName varchar(20), LastName
varchar(20), staffType varchar(20))
insert into Staff values
(1, 'Adam', 'Sorme', 'Student'),
(2, 'Lara', 'Sandra', 'Teacher'),
(3, 'Jack', 'Jones', 'Student')
IF OBJECT_ID('dbo.Gates') IS NOT NULL DROP TABLE Gates
create table Gates (GateId int, GateName varchar(20))
insert into Gates values
(1, 'frontDoor'),
(2, 'backDoor')
IF OBJECT_ID('dbo.Transitions') IS NOT NULL DROP TABLE Transitions
create table Transitions (Id int, transitionDate datetime, GateId int,
StaffId int)
insert into Transitions values
(1, '2018-01-1 08:00:00', 1, 1),
(2, '2018-01-1 10:00:00', 2, 1),
(3, '2018-01-1 20:00:00', 2, 1),
(4, '2018-01-2 07:00:00', 1, 2),
(5, '2018-01-2 10:00:00', 2, 3),
(6, '2018-01-9 12:00:00', 2, 2)
--select * from Transitions
DECLARE @Datefrom DATETIME = '2018-01-01'
DECLARE @DateTo DATETIME = '2018-01-03'
----1. If the transition table itself is not reliable meaning there
--could be imports and the maxID could be for a lesser datetime
IF OBJECT_ID('tempdb..#Transitions') IS NOT NULL DROP TABLE
#Transitions
SELECT *, [GateSortID] = RANK() OVER (PARTITION BY StaffID ORDER BY
StaffID,GateID,TransitionDate)
INTO #Transitions
FROM Transitions
----2.Based on above temp table get first and last dates
IF OBJECT_ID('tempdb..#FirstandLastDates') IS NOT NULL DROP TABLE
#FirstandLastDates
SELECT T.StaffId,
[FirstDate] = FirstDate.transitionDate,
[LastDate] = LastDate.transitionDate
INTO #FirstandLastDates
FROM #Transitions T
JOIN
(
SELECT TT.StaffId,
[MinGateSortID] = MIN(GateSortID),
TT.GateID,
G.transitionDate
FROM #Transitions TT
JOIN Transitions G
ON TT.StaffId = G.StaffId
AND TT.Id = G.ID
AND TT.GateId = G.GateId
WHERE GateSortID = 1-- MIN VALUE WILL ALWAYS BE 1
GROUP BY TT.StaffID,TT.GateID,G.transitionDate
)FirstDate --lol!!
ON T.StaffID= FirstDate.StaffID
LEFT JOIN
(
SELECT TT.StaffId, TT.GateId, G.TransitionDate
FROM #Transitions TT
JOIN #Transitions G
ON TT.StaffId = G.StaffId
AND TT.Id = G.ID
AND TT.GateId = G.GateId
JOIN
(
SELECT StaffID,
[MaxGateSortID] = MAX(GateSortID)
FROM #Transitions TT
WHERE GateSortID <> 1 -- SO THAT IF THE PERSON HAS NOT --CLOCKED OUT YET ONLY CLOCKED IN DO NOT CONSIDER THAT THE
--GATES ARE SAME
GROUP BY StaffID
) LastGate1
ON TT.StaffId = LastGate1.StaffId
AND TT.GateSortID = LastGate1.MaxGateSortID
)LastDate
ON T.StaffId = LastDate.StaffId
GROUP BY T.StaffId,FirstDate.transitionDate,LastDate.transitionDate
----3.Based on above temp table get first and last transition gates
IF OBJECT_ID('tempdb..#FirstandLastGates') IS NOT NULL DROP TABLE
#FirstandLastGates
SELECT T.StaffId,
[FirstGate] = FirstGate.GateName,
[LastGate] = LastGate.GateName
INTO #FirstandLastGates
FROM #Transitions T
JOIN
(
SELECT StaffID,
[MinGateSortID] = MIN(GateSortID),
TT.GateID,
GateName
FROM #Transitions TT
JOIN Gates G
ON TT.GateId = G.GateId
WHERE GateSortID = 1-- MIN VALUE WILL ALWAYS BE 1
--AND TT.transitionDate BETWEEN @Datefrom AND @DateTo
GROUP BY StaffID,TT.GateID,GateName
)FirstGate
ON T.StaffID= FirstGate.StaffID
LEFT JOIN
(
SELECT TT.StaffId, TT.GateId, G.GateName
FROM #Transitions TT
JOIN Gates G
ON TT.GateId = G.GateId
JOIN
(
SELECT StaffID,
[MaxGateSortID] = MAX(GateSortID)
FROM #Transitions TT
WHERE GateSortID <> 1 -- SO THAT IF THE PERSON HAS NOT CLOCKED
-- OUT YET ONLY CLOCKED IN DO NOT CONSIDER THAT THE GATES ARE --SAME
--AND TT.transitionDate BETWEEN @Datefrom AND @DateTo
GROUP BY StaffID
) LastGate1
ON TT.StaffId = LastGate1.StaffId
AND TT.GateSortID = LastGate1.MaxGateSortID
)LastGate
ON T.StaffId = LastGate.StaffId
GROUP BY T.StaffId,FirstGate.GateName,LastGate.GateName
--MAIN OUTPUT
SELECT DISTINCT --t.Id,
--t.transitionDate,
[MinTransitionDate] = D.FirstDate,
[MaxTransitionDate] = D.LastDate,
[FirstGateName] = G.FirstGate,
[LastGateName] = G.LastGate,
T.[StaffId],
S.StaffType
from Staff S
JOIN #Transitions T
ON S.StaffId = T.StaffId
JOIN #FirstandLastDates D
ON T.StaffId = D.StaffId
JOIN #FirstandLastGates G
ON T.StaffId = G.StaffId
GROUP BY t.Id, D.FirstDate, D.LastDate, G.FirstGate,G.LastGate,T.[StaffId],
S.StaffType