TSQL:给定分区的最高记录(有条件)

时间:2016-06-30 00:27:03

标签: sql sql-server tsql group-by partitioning

我需要获取TABLE_A中的所有记录,其中至少 2 最后Status是空的(相对于Inspection_Date)和{{1} } Room_ID中不存在。

这是我用作示例的简化表:

TABLE_A

TABLE_B

表-B

  Room_Id   Status    Inspection_Date
  -------------------------------------
    1        vacant      5/15/2015
    2        occupied    5/21/2015
    2        vacant      1/19/2016
    1        occupied   12/16/2015
    4        vacant      3/25/2016
    3        vacant      8/27/2015
    1        vacant      4/17/2016
    3        vacant     12/12/2015
    3        vacant      3/22/2016
    4        occupied    2/2/2015
    4        vacant      3/24/2015

我的结果应如下所示:

  Room_Id   Status    Inspection_Date
  ------------------------------------
    1        vacant       5/15/2015
    2        occupied     5/21/2015
    2        vacant       1/19/2016
    1        vacant      12/16/2015
    1        vacant       4/17/2016

我试过这种方式,它适用于示例,但不能处理我的数据..逻辑不完整:

   Room_Id  Status  Inspection_Date
   ---------------------------------
    3       vacant      8/27/2015
    3       vacant     12/12/2015
    3       vacant      3/22/2016
    4       occupied    2/2/2015
    4       vacant      3/24/2015
    4       vacant      3/25/2016

这是架构:

 With cteA As
(
Select *, Row_Number() Over (Partition By Room_ID, Status Order By     Inspection_Date Desc) RowNum From Table_A 
)
Select * From Table_A Where Room_Id In
(
Select Room_Id 
    From cteA
    Where Room_Id Not In (Select Room_Id From Table_B) 
        And Status = 'vacant' And RowNum > 1 
)
    Order By Room_Id, Inspection_Date

4 个答案:

答案 0 :(得分:1)

<强> PLAIN

  1. 对于TABLE_A中的每个房间,选择最后一个日期(作为lastDate)

  2. TABLE_A中的每个房间选择上一个日期(作为prevLastDate)

  3. 从lastDate获取room_ids,状态为'vacant'(作为lastDateVacant)

  4. 从prevLastDate获取room_ids,其状态为'空置'(as prevLastDateVacant)

  5. 过滤TABLE_A只包含lastDateVacant和prevLastDateVacant(内部)中的ID

  6. 过滤TABLE_A,使其只有不在TABLE_B中的ID(左外+ IS NULL)

  7. 结果你有:

    WITH lastDate AS (
        SELECT room_id AS room,MAX(inspection_date) AS date
        FROM "TABLE_A"
        GROUP BY room_id
    ), prevLastDate AS (
        SELECT room_id AS room,MAX(inspection_date) AS date
        FROM "TABLE_A" a
        INNER JOIN lastDate ON a.room_id = lastDate.room and a.inspection_date < lastDate.date
        GROUP BY room_id
    ), lastDateVacant AS (
        SELECT room_id AS room FROM "TABLE_A"
        WHERE (room_id,inspection_date) IN (
            SELECT room, date FROM lastDate
        ) AND status = 'vacant' 
    ), prevLastDateVacant AS (
        SELECT room_id AS room FROM "TABLE_A"
        WHERE (room_id,inspection_date) IN (
            SELECT room, date FROM prevLastDate
        ) AND status = 'vacant' 
    )
    
    SELECT a.* FROM "TABLE_A" a 
    INNER JOIN lastDateVacant 
        ON a.room_id = lastDateVacant.room
    INNER JOIN prevLastDateVacant 
        ON a.room_id = prevLastDateVacant.room
    LEFT OUTER JOIN "TABLE_B" AS b 
        ON a.room_id = b.room_id    
    WHERE b.room_id IS NULL 
    ORDER BY a.room_id ASC, a.inspection_date DESC
    

    窗口功能

    不确定TSQL的语法是否相同,但这是较短的变体:

    1. 按房间划分和按日期排序

    2. 检查排名为1和2的ID为“空置”状态的ID,按ID分组并多次出现

    3. 带房间AS(     选择房间(         选择room_id作为房间,状态,inspection_date作为日期,         RANK()OVER(由room_id ORDER BY inspection_date DESC划分)作为排名         来自“TABLE_A”     )     where(排名在(1,2)和status ='vacant')     按房间分组     有计数()&gt; 1 ) 选择a。 FROM“TABLE_A”a INNER JOIN会议室     在a.room_id = room.room LEFT OUTER JOIN“TABLE_B”AS b     在a.room_id = b.room_id
      在哪里b.room_id是空的 ORDER BY a.room_id ASC,a.inspection_date DESC

答案 1 :(得分:0)

您的条件几乎直接转换为查询。您可以使用窗口函数进行空置计数,将not exists用于与table_b的关系:

select a.*
from (select a.*,
             sum(case when status = 'vacant' then 1 else 0 end) over (partition by room_id) as num_vacant
      from table_a a
      where not exists (select 1
                        from table_b b
                        where b.room_id = a.room_id
                       )
    ) a
where num_vacant >= 2;

编辑:

如果你想让最后两个空缺,你可以找到最后一个非空的记录,然后计算那些大于那个的记录:

select a.*
from (select a.*,
             sum(case when a2.max_nonvacant > a.inspection_date then 0 else 1) over (partition by room_id) as num_vacant_last
      from table_a a outer apply
           (select max(inspection_date) as max_nonvacant
            from table_a a2
            where a2.room_id = a.room_id and a2.status <> 'vacant'
           ) a2
      where not exists (select 1
                        from table_b b
                        where b.room_id = a.room_id
                       )
    ) a
where num_vacant_last >= 2;

答案 2 :(得分:0)

我做了这个测试: 提取考虑到与inspection_date(降序)相关的最后两个状态(相等状态)的所有room_id:

//example function which receives the sent data as well
function exampleLoggingCallback(sentData, receivedData, textStatus, jqXhr) {
    console.log('Sent data: ' + sentData);
    console.log('Received data: ' + receivedData);
}

//example call to your ajax function:
yourCustomAjaxFunction({foo: 'bar'}, exampleLoggingCallback);

答案 3 :(得分:0)

这对我有用,我一次又一次地检查过。

with Rooms as (
select
    Room_Id, Status,
    row_number() over (partition by Room_Id order by Inspection_Date desc) as rn
from TABLE_A
), Candidates as (
select Room_Id from Rooms group by Room_Id
having sum(case when rn in (1, 2) and Status = 'vacant' then 1 else null end) = 2
)
select * from TABLE_A
where Room_Id in (select Room_Id from Candidates except select Room_Id from TABLE_B)
order by Room_Id, Inspection_Date desc