【问题标题】:T-SQL: Conditional Existential groupingT-SQL:条件存在分组
【发布时间】:2016-07-01 01:39:01
【问题描述】:

我需要在TABLE_A 中获取所有Room_IDs,其中Room_IDs 的每个实例的最后两个或更多Status 连续空置(相对于Inspection_Date)并且在@987654326 中不存在@。

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

TABLE_A

  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

TABLE_B

  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

这是架构:

CREATE TABLE TABLE_A (`Room_Id` int, 
                      `Status` varchar(55), 
                      `Inspection_Date` varchar(55)
                     );

INSERT INTO TABLE_A (`Room_Id`, `Status`, `Inspection_Date`)
VALUES  (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');

CREATE TABLE TABLE_B (`Room_Id` int, 
                      `Status` varchar(55),         
                      `Inspection_Date` varchar(55)
                     );

INSERT INTO TABLE_B (`Room_Id`, `Status`, `Inspection_Date`)
VALUES
        (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'),;

【问题讨论】:

  • table_b 中不存在 room_id?或者您想在两列或全部三列上进行匹配?
  • Room_ID 不在 table_B 中,谢谢询问
  • 如果您有像Inspection_Date 这样的列 - 您应该使用最合适的数据类型 - 而varchar(55)肯定不是。使用@ 987654333@(如果您只需要日期),或者DATETIME2(n),如果您还需要时间部分。另外:放弃那些烦人的反引号 - 那是 MySQL,它们在 T-SQL 中没有意义或不需要这些
  • @marc_s 这是为了方便使用。我显然在我的表上使用了 Date 数据类型。这里还有后面的勾号,因为我从消息 stackoverflow 的早期部分复制粘贴了列名,将它们用作code 的“迷你降价格式化工具”。不过谢谢你..

标签: sql sql-server tsql group-by


【解决方案1】:

考虑这种方法:

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

在此处查看正在运行的查询:http://rextester.com/VXBRFF91880

【讨论】:

  • 我之前尝试过,但不幸的是逻辑不起作用,还是谢谢你的帮助!
  • @Hamza 我确实不小心遗漏了您可能已经注意到的where 子句的关键部分。但除此之外,我很想知道哪个部分不符合您的要求。
  • 是的,你说得对,对不起,我不得不处理其他事情,但我确实看到了我的代码的问题。谢谢!
【解决方案2】:

这会根据样本数据提供您正在寻找的结果。 ps 感谢您提供创建表和插入语句。

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

【讨论】:

    【解决方案3】:

    另一种方式:

    ;WITH cte AS (
    SELECT DISTINCT a.Room_Id,
            COUNT(a.Inspection_Date) OVER(PARTITION BY a.Room_Id,a.[Status]  ORDER BY a.[Status]) as d
    FROM TABLE_A a
    FULL OUTER JOIN TABLE_B b
        ON a.Room_Id = b.Room_Id and a.Inspection_Date = b.Inspection_Date
    WHERE b.Room_Id IS NULL and a.[Status] = 'vacant'
    )
    
    SELECT a.*
    FROM cte c
    INNER JOIN TABLE_A a
        ON a.Room_Id = c.Room_Id
    

    输出:

    Room_Id Status      Inspection_Date
    4       vacant      3/25/2016
    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】:

      所有的答案对于某个现存的都是正确的,但从来没有给我Room_IDs 的每个实例的最后两个Status 空缺:

      我找到了答案

               WITH lastDate AS ( SELECT Room_ID  ,MAX(Inspection_Date) AS [date]
                              FROM TableA
                              GROUP BY Room_ID), 
                prevLastDate AS ( SELECT a.Room_ID  ,MAX(Inspection_Date) AS [date]
                                  FROM TableA a
                                  INNER JOIN lastDate ON a.Room_ID = lastDate.Room_ID and a.Inspection_Date < lastDate.[date]
                                  GROUP BY a.Room_ID), 
                lastDateVacant AS ( SELECT Room_ID   
                                    FROM TableA
                                    WHERE Room_ID IN ( SELECT Room_ID FROM lastDate) 
                                    AND Inspection_Date IN ( SELECT [date] FROM lastDate) 
                                    AND Status = 'Vacant'),
                prevLastDateVacant AS ( SELECT Room_ID   
                                        FROM TableA
                                        WHERE Room_ID IN ( SELECT Room_ID FROM prevLastDate) 
                                        AND Inspection_Date IN ( SELECT [date] FROM prevLastDate) 
                                        AND Status = 'Vacant')
      
          SELECT a.* 
          FROM TableA a 
          INNER JOIN lastDateVacant 
              ON a.Room_ID = lastDateVacant.Room_ID
          INNER JOIN prevLastDateVacant 
              ON a.Room_ID = prevLastDateVacant.Room_ID
          LEFT OUTER JOIN preservation.. 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
      

      【讨论】:

      • 我不认为这是一个有效的 SQL Server 查询。
      • @shawnt00 是的,我现在在 prod 中使用它,我确保手动检查。
      • 我已经稍微修正了语法并仔细检查了.. 它仍然有效 1. 对于 TableA 中的每个房间,我们选择最后一个日期(作为 lastDate) 2. 对于 TableA 中的每个房间,我们选择上一个日期(如 prevLastDate) 3. 我们从 lastDate 获得 Room_ID,其状态为 'vacant'(如 lastDateVacant) 4. 我们从 prevLastDate 获得 Room_ID,其 Status 为 'vacant'(如 prevLastDateVacant) 5. 我们过滤为只有 Room_ID它们在 lastDateVacant 和 prevLastDateVacant (inner) 6. 我们过滤到只有不在 TableB 中的 Room_ID (left outer + IS NULL)
      • @shawnt00 我在这里复制了错误的查询,对此感到抱歉.. 但就像我之前说的那样,我已经修复了语法。并粘贴正确的 TSQL 查询。
      猜你喜欢
      • 1970-01-01
      • 2020-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 2017-05-24
      • 2011-06-06
      • 1970-01-01
      相关资源
      最近更新 更多