[英]T-SQL Max date and min date with value single row
首先,我要感謝幫助這個復雜而困難的查詢的朋友。
我有三張桌子
表格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'
OUTPUT:
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
您可以嘗試如下查詢
create table staff(StaffId int, FirstName nvarchar(10), LastName nvarchar(10), staffType nvarchar(10))
insert into staff values
(1,'Adam','Sorme','Student')
,(2,'Lara','Sandra','Teacher')
,(3,'Jack','Jones','Student')
go
create table gate(GateId int, GateName nvarchar(10))
insert into gate values
(1,'frontDoor')
,(2,'superDoor')
go
create table logs
(Id int, transitionDate datetime, GateId int, StaffId int)
insert into logs 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',1,3)
,(6,'2018-01-9 12:00:00',2,2)
go
declare @startdate datetime, @enddate datetime
select @startdate='2018-01-1 00:00:00' , @enddate='2018-01-03 00:00:00'
; with tempSet as
(
select
transitionDatetime=l.transitionDate,
gateName=g.gateName,
staffid=l.staffid,
idx=
row_number() over(partition by l.staffid order by l.transitionDate ) -
row_number() over(partition by l.staffid,cast(l.transitionDate as date) order by l.transitionDate ),
transitionDate=cast(l.transitionDate as date)
from
logs l inner join staff s on
l.staffid=s.staffid and staffType='Student'
join gate g on g.gateid=l.gateid
)
, groupedSet as
(
select
t1.*,
FirstGateName=t2.gatename,
lastGateName=t3.gatename
from
(
select
staffid,
mintransitionDate=min(transitionDatetime),
maxtransitionDate= case when count(1)>1 then max(transitionDatetime) else null end,
transitionDate=max(transitionDate),
idx
from
tempSet
group by staffid,idx
) t1
left join
tempSet t2
on t1.idx=t2.idx
and t1.staffid=t2.staffid and t1.mintransitionDate=t2.transitionDatetime
left join
tempSet t3
on t1.idx=t3.idx
and t1.staffid=t3.staffid and t1.maxtransitionDate=t3.transitionDatetime
where t1.transitionDate between @startdate and @enddate
)
select
t.*,
g.mintransitionDate,
g.maxtransitionDate,
g.FirstGateName,
g.LastGateName
from
groupedSet g
right join
(
select
d,
staffid
from
(
select
top (select datediff(d,@startdate, @endDate))
d=dateadd(d,row_number() over(order by (select null))-1, @startDate)
from
sys.objects o1 cross join sys.objects o2
)tally
cross join
staff
where staff.stafftype='Student'
)t
on cast(t.d as date)=cast(g.transitionDate as date) and t.staffid=g.staffid
order by t.d asc, t.staffid asc
所有插入語句:
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')
create table #Gates (GateId int, GateName varchar(20))
insert into #Gates values
(1, 'frontDoor'),
(2, 'backDoor')
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', 1, 3),
(6, '2018-01-9 12:00:00', 2, 2)
為了獲得理想的結果,您將需要CTE,且每天的時間間隔都在此范圍內。 您在以下查詢中包含的變量中指定的范圍的限制(日期)。
declare @maxTransitionDate datetime, @minTransitionDate datetime
select @maxTransitionDate='2018-01-10', @minTransitionDate='2018-01-01'
;with cte as (
select @minTransitionDate [Days]
union all
select dateadd(day,1,[Days]) from cte where [Days] < @maxTransitionDate
)
,cte2 as (
select [Days], [StaffId], [FirstName], [LastName] from cte cross apply #staff where stafftype ='Student'
)
select C.[Days] [Date], C.[staffid], C.FirstName, C.LastName, A.mintransitiondate, A.[maxtransitiondate], A.firstgatename, A.lastgatename, A.staffType from (
select T.[Date],
T.staffid,
T.mintransitiondate,
case when T.maxtransitiondate <> T.mintransitiondate then T.maxtransitiondate end [maxtransitiondate],
(select gatename from #gates where gateid = T.firstgateid) firstgatename,
(select gatename from #gates where gateid = T.lastgateid) lastgatename,
S.FirstName,
S.LastName,
S.staffType
from (
select [date], staffid,
max(case when rn = 1 then transitiondate end) mintransitiondate,
max(case when rn = cnt then transitiondate end) maxtransitiondate,
max(case when rn = 1 then GateId end) FirstGateId,
max(case when rn = cnt then GateId end) LastGateId
from (
select *, cast(transitiondate as date) [Date],
row_number() over (partition by staffid, cast(transitiondate as date) order by transitiondate) [rn],
count(*) over (partition by staffid, cast(transitiondate as date)) [cnt]
from #Transitions
) a group by staffid, [date]
) [T] join #Staff [S] on T.staffid = S.staffid
where S.staffType = 'Student'
) [A] right join cte2 [C] on A.[Date] = C.[Days] and A.[staffid] = C.[staffid]
其他答案似乎太復雜了。
首先,使用cross join
獲取所有行。 然后使用left join
和聚合來獲取所需的信息。
基本查詢如下所示:
select s.staffId, d.dte,
min(t.transitionDate) as first_change,
max(t.transitionDate) as first_change,
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;
您可以增強select
以帶回更多列。
這是一個SQL Fiddle。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.