使用Sql双列时的T-SQL案例

时间:2018-02-13 22:09:56

标签: sql sql-server tsql

首先,我要感谢帮助这个复杂而困难的查询的朋友们。

我有三张桌子

表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

see working demo

问题:4.行中的max_date为空。我希望last_gateid的值为null。你能帮帮我吗?

屏幕截图4.行 https://cdn.pbrd.co/images/H7vyu31.png

3 个答案:

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