如何对复杂表格进行分区

时间:2015-08-11 09:09:24

标签: sql-server tsql partitioning

我在SQL Server中有一个名为CHECKINOUT的表,该表包含以下列:

PASSID  CHECKTIME               CHECKTYPE   UID
--------------------------------------------------
PS3 2015-08-05 01:12:02.100     0       CAA0322
PS3 2015-08-06 02:17:02.310     1       CAA0322
PS4 2015-08-03 01:02:03.200     0       CAA0322
PS4 2015-08-03 11:11:01.233     1       CAA0322
PS3 2015-08-02 11:11:01.210     0       CAA0322
PS3 2015-08-02 12:02:04.147     1       CAA0322
PS1 2015-09-05 11:11:01.210     0       CAA0322
PS1 2015-09-05 01:12:09.010     1       CAA0322

PASSID是每次有人访问场所时允许的传递,当他们被允许进入时,他们的签到时间被注册并且Checktype变为0

   CHECKTYPE=0

当他们结账时,他们结帐的时间也会在检查时再次登记,但这次是 checktype标志变为1

   CHECKTYPE=0

现在在一天结束的时候,我希望看到每次通过的报告,无论它输入和输出的次数是多少次

PASSID  CheckInTime             CheckOutTime                     UID
PS1 2015-08-05 01:12:02.100     2015-08-06 02:17:02.310     CAA0322
PS3 2015-08-05 01:12:02.100     2015-08-06 02:17:02.310     CAA0322
PS3 2015-08-02 11:11:01.210     2015-08-02 12:02:04.147     CAA0322
PS4 2015-08-03 01:02:03.200     22015-08-03 11:11:01.233    CAA0322

以上结果显示如下

  • CheckInTime是desc
  • 中该ID的checktype = 0的第一个检查时间
  • CheckOutTime是desc
  • 中该ID的checktype = 1的第一个检查时间

我尝试使用分区但是我失败了,我只能返回一条记录,但是我希望看到我的代码在下面的所有记录,但它只返回一条记录,我希望在不指定任何passid的情况下返回所有记录

declare @PassID varchar(30)='PS3';

with LastEntryData(PASSID, CHECKTIME, CHECKTYPE, GateID, UID)
as 
(
    select top 2 
        c.PASSID, c.CHECKTIME, c.CHECKTYPE, c.GateID, c.UID     
    from 
        CHECKINOUT c
    where 
        c.PASSID = @PassID
    order by 
        c.CHECKTIME desc
    ),
    CheckInTime(CHECKTIME) as
    (
        select 
            i.CHECKTIME 
        from 
            LastEntryData i
        where 
            i.CHECKTYPE = 0),
    CheckOutTime(CHECKTIME) as
    (
        select 
            i.CHECKTIME 
        from 
            LastEntryData i
        where 
            i.CHECKTYPE = 1)
select 
    l.PASSID, CheckInTime = i.CHECKTIME,
    CheckOutTime = o.CHECKTIME, l.UID 
from 
    LastEntryData l, CheckInTime i, CheckOutTime o
group by 
    l.PASSID, l.GateID, l.UID, i.CHECKTIME, o.CHECKTIME

1 个答案:

答案 0 :(得分:0)

让我们做一张桌子。 (如果这样做,你会得到更多答案。)

didFinishLaunching

我会做一些有根据的猜测,因为您的样本数据与您的预期输出不匹配。

此查询(在PostgreSQL中)返回所有检查时间。

create table checkinout (
  passid char(3) not null,
  checktime timestamp not null default current_timestamp,
  checktype integer not null check (checktype in (1, 0)),
  uid char(7) not null
);

insert into checkinout values
('PS3', '2015-08-05 01:12:02.100',     0,       'CAA0322'),
('PS3', '2015-08-06 02:17:02.310',     1,       'CAA0322'),
('PS4', '2015-08-03 01:02:03.200',     0,       'CAA0322'),
('PS4', '2015-08-03 11:11:01.233',     1,       'CAA0322'),
('PS3', '2015-08-02 11:11:01.210',     0,       'CAA0322'),
('PS3', '2015-08-02 12:02:04.147',     1,       'CAA0322'),
('PS1', '2015-09-05 11:11:01.210',     0,       'CAA0322'),
('PS1', '2015-09-05 01:12:09.010',     1,       'CAA0322');
uid       passid  time_in
--
CAA0322   PS1     2015-09-05 11:11:01.21
CAA0322   PS3     2015-08-02 11:11:01.21
CAA0322   PS3     2015-08-05 01:12:02.1
CAA0322   PS4     2015-08-03 01:02:03.2

子查询将返回结帐时间。这将在几乎任何SQL dbms上运行。

select uid, passid, checktime as time_in
from checkinout
where checktype = 0
order by uid, passid, checktime;
uid       passid  time_in                 time_out
--
CAA0322   PS1     2015-09-05 11:11:01.21  
CAA0322   PS3     2015-08-02 11:11:01.21  2015-08-02 12:02:04.147
CAA0322   PS3     2015-08-05 01:12:02.1   2015-08-06 02:17:02.31
CAA0322   PS4     2015-08-03 01:02:03.2   2015-08-03 11:11:01.233

错误的数据解释了NULL。

如果您的数据和人员表现良好,并且您的平台支持分析功能,则可以使用lead()或lag()将各个部分组合在一起。 (我认为SQL Server 2012+支持lead()和lag()。)

select 
  t1.uid, t1.passid, t1.checktime,
  (select min(checktime) 
   from checkinout 
   where uid = t1.uid 
     and passid = t1.passid 
     and checktime >= t1.checktime
     and checktype = 1) as time_out
from checkinout t1
where checktype = 0
order by t1.uid, t1.passid, t1.checktime;