Sql server 计算同一UnitID的不同行中日期之间的天数

Sql server 计算同一UnitID的不同行中日期之间的天数,sql-server,Sql Server,我试图计算一个商业房地产空置的时间。我有每个入住该单元的租户的入住和迁出日期。由于数据位于同一行中,因此很容易计算每个租户的占用时间。但是,我想计算空置时间:从迁出前一个租户到迁入下一个租户之间的时间。这些日期显示在单独的行中 以下是我目前拥有的一个样本: SELECT uni_vch_UnitNo AS UnitNumber, uty_vch_Code AS UnitCode, uty_int_Id AS UnitID, tul_int_FacilityId A

我试图计算一个商业房地产空置的时间。我有每个入住该单元的租户的入住和迁出日期。由于数据位于同一行中,因此很容易计算每个租户的占用时间。但是,我想计算空置时间:从迁出前一个租户到迁入下一个租户之间的时间。这些日期显示在单独的行中

以下是我目前拥有的一个样本:

SELECT 
    uni_vch_UnitNo AS UnitNumber, 
    uty_vch_Code AS UnitCode, 
    uty_int_Id AS UnitID,  tul_int_FacilityId AS FacilityID, 
    tul_dtm_MoveInDate AS Move_In_Date, 
    tul_dtm_MoveOutDate AS Move_Out_Date, 
    DATEDIFF(day, tul_dtm_MoveInDate, tul_dtm_MoveOutDate) AS Occupancy_Days
FROM TenantUnitLeases
JOIN units
    ON tul_int_UnitId = uni_int_UnitId
JOIN UnitTypes
    ON uni_int_UnitTypeId = uty_int_Id
WHERE 
    tul_int_UnitId = '26490'
ORDER BY tul_dtm_MoveInDate ASC

是否有办法按时间顺序为每一行分配一个id,并找出第2行的入住日期与第1行的迁出日期之间的差异,依此类推


提前感谢您的帮助。

这需要一个窗口函数或相关子查询。目标是为每一行提供上一个移出日期,这又是该行的一个函数。在此上下文中,术语“窗口”意味着在比整个集合更小的范围内应用聚合函数

如果您有一个名为GetPreviousMoveOutDate的函数,那么这些参数将是要进行筛选的键,以及要在筛选中搜索的范围。因此,我们将传递
UnitID
作为此行的键和
MoveInDate
,函数应返回传入日期之前相同单元的最新
MoveOutDate
。通过在此日期之前获取最长日期,我们将确保仅获取以前的入住率(如果存在)

要在ANSI-SQL中使用子查询,只需添加select作为列。这应该适用于MS-SQL以及其他数据库平台;但是,它需要为表名使用别名,以便可以在查询中多次引用它们。我已经使用
AS
语法用别名更新了示例SQL,尽管它看起来与表命名约定无关。我在
units
表中添加了一个
uni\u dtm\u UnitFirstAvailableDate
,以处理第一个空缺,但这可以是默认值:

SELECT 
    uni.uni_vch_UnitNo AS UnitNumber, 
    uty.uty_vch_Code AS UnitCode, 
    uty.uty_int_Id AS UnitID,  tul_int_FacilityId AS FacilityID, 
    tul.tul_dtm_MoveInDate AS Move_In_Date, 
    tul.tul_dtm_MoveOutDate AS Move_Out_Date, 
    DATEDIFF(day, tul.tul_dtm_MoveInDate, tul.tul_dtm_MoveOutDate) AS Occupancy_Days,
    --  select the date:
    (SELECT MAX (prev_tul.tul_dtm_MoveOutDate ) 
         FROM  TenantUnitLeases AS prev_tul
         WHERE prev_tul.tul_int_UnitId = tul.tul_int_UnitId
             AND  prev_tul.tul_dtm_MoveOutDate > tul.tul_dtm_MoveInDate
                 AND prev_tul.tul_dtm_MoveOutDate is not null
       ) AS previous_moveout,
    -- use the date in a function:
    DATEDIFF(day, tul.tul_dtm_MoveInDate, 
           ISNULL(
            (SELECT MAX (prev_tul.tul_dtm_MoveOutDate ) 
         FROM  TenantUnitLeases AS prev_tul
         WHERE prev_tul.tul_int_UnitId = tul.tul_int_UnitId
             AND  prev_tul.tul_dtm_MoveOutDate > tul.tul_dtm_MoveInDate
                AND prev_tul.tul_dtm_MoveOutDate is not null
       ) ,  uni.uni_dtm_UnitFirstAvailableDate)  -- handle first occupancy
     ) AS Vacancy_Days

FROM TenantUnitLeases AS tul
JOIN units AS uni
    ON  tul.tul_int_UnitId = uni.uni_int_UnitId
JOIN UnitTypes AS uty
    ON uni.uni_int_UnitTypeId = uty.uty_int_Id
WHERE 
    tul.tul_int_UnitId = '26490'
ORDER BY  tul.tul_dtm_MoveInDate ASC

这需要一个窗口函数或相关子查询。目标是为每一行提供上一个移出日期,这又是该行的一个函数。在此上下文中,术语“窗口”意味着在比整个集合更小的范围内应用聚合函数

如果您有一个名为GetPreviousMoveOutDate的函数,那么这些参数将是要进行筛选的键,以及要在筛选中搜索的范围。因此,我们将传递
UnitID
作为此行的键和
MoveInDate
,函数应返回传入日期之前相同单元的最新
MoveOutDate
。通过在此日期之前获取最长日期,我们将确保仅获取以前的入住率(如果存在)

要在ANSI-SQL中使用子查询,只需添加select作为列。这应该适用于MS-SQL以及其他数据库平台;但是,它需要为表名使用别名,以便可以在查询中多次引用它们。我已经使用
AS
语法用别名更新了示例SQL,尽管它看起来与表命名约定无关。我在
units
表中添加了一个
uni\u dtm\u UnitFirstAvailableDate
,以处理第一个空缺,但这可以是默认值:

SELECT 
    uni.uni_vch_UnitNo AS UnitNumber, 
    uty.uty_vch_Code AS UnitCode, 
    uty.uty_int_Id AS UnitID,  tul_int_FacilityId AS FacilityID, 
    tul.tul_dtm_MoveInDate AS Move_In_Date, 
    tul.tul_dtm_MoveOutDate AS Move_Out_Date, 
    DATEDIFF(day, tul.tul_dtm_MoveInDate, tul.tul_dtm_MoveOutDate) AS Occupancy_Days,
    --  select the date:
    (SELECT MAX (prev_tul.tul_dtm_MoveOutDate ) 
         FROM  TenantUnitLeases AS prev_tul
         WHERE prev_tul.tul_int_UnitId = tul.tul_int_UnitId
             AND  prev_tul.tul_dtm_MoveOutDate > tul.tul_dtm_MoveInDate
                 AND prev_tul.tul_dtm_MoveOutDate is not null
       ) AS previous_moveout,
    -- use the date in a function:
    DATEDIFF(day, tul.tul_dtm_MoveInDate, 
           ISNULL(
            (SELECT MAX (prev_tul.tul_dtm_MoveOutDate ) 
         FROM  TenantUnitLeases AS prev_tul
         WHERE prev_tul.tul_int_UnitId = tul.tul_int_UnitId
             AND  prev_tul.tul_dtm_MoveOutDate > tul.tul_dtm_MoveInDate
                AND prev_tul.tul_dtm_MoveOutDate is not null
       ) ,  uni.uni_dtm_UnitFirstAvailableDate)  -- handle first occupancy
     ) AS Vacancy_Days

FROM TenantUnitLeases AS tul
JOIN units AS uni
    ON  tul.tul_int_UnitId = uni.uni_int_UnitId
JOIN UnitTypes AS uty
    ON uni.uni_int_UnitTypeId = uty.uty_int_Id
WHERE 
    tul.tul_int_UnitId = '26490'
ORDER BY  tul.tul_dtm_MoveInDate ASC

我真的不知道哪些表为您的查询提供了哪些列。今后请使用别名和dot对其进行限定

如果您使用的是SQL 2012或更高版本,那么您已经有了LEAD和LAG函数,它们可以完全满足您的需要:将“leading”或“laging”行放入当前行。看看这是否有效(希望它至少能让你开始):


我真的不知道哪些表为您的查询提供了哪些列。今后请使用别名和dot对其进行限定

如果您使用的是SQL 2012或更高版本,那么您已经有了LEAD和LAG函数,它们可以完全满足您的需要:将“leading”或“laging”行放入当前行。看看这是否有效(希望它至少能让你开始):


lag()
函数提供的功能是将当前行中的值与前一行中的值进行比较

在查询中尝试以下操作:

select...
tul_dtm_MoveInDate AS Move_In_Date, 
tul_dtm_MoveOutDate AS Move_Out_Date, 
DateDiff(day, Lag(tul_dtm_MoveOutDate,1) over(partition by uty_vch_Code, tul_int_FacilityId  order by tul_dtm_MoveInDate), tul_dtm_MoveInDate) DaysVacant,
...

lag()
函数提供的功能是将当前行中的值与前一行中的值进行比较

在查询中尝试以下操作:

select...
tul_dtm_MoveInDate AS Move_In_Date, 
tul_dtm_MoveOutDate AS Move_Out_Date, 
DateDiff(day, Lag(tul_dtm_MoveOutDate,1) over(partition by uty_vch_Code, tul_int_FacilityId  order by tul_dtm_MoveInDate), tul_dtm_MoveInDate) DaysVacant,
...

非常感谢你的帮助,这个社区很棒。我正在工作中学习SQL,没有人去问问题,所以这个平台是我唯一的生命线。当我运行您的查询时,上一个_时差列为每一行返回“2020-07-06”中相同的上一个时差,而不是每个时差的上一个时差。从我在网上读到的其他文章中也有类似的问题,也许RN函数在这里是关键?我不是专家。再次感谢,非常感谢您的帮助。@Casey,我编辑了SQL以避免空值或相等的移出日期。您可以在子选择中进一步使用连接以获得不同的结果。Lag和RowNumber更简单,工作也很好,但它们是MS-SQL特有的,所以您需要在其他数据库上学习其他内容。我总是先尝试用ANSI-SQL完成它,因为这些知识可以在许多其他DB引擎上使用。祝你好运非常感谢你的帮助,这个社区很棒。我正在工作中学习SQL,没有人去问问题,所以这个平台是我唯一的生命线。当我运行您的查询时,上一个_时差列为每一行返回“2020-07-06”中相同的上一个时差,而不是每个时差的上一个时差。从我在网上读到的其他文章中也有类似的问题,也许RN函数在这里是关键?我不是专家。再次感谢,非常感谢您的帮助。@Casey,我编辑了SQL以避免空值或相等的移出日期。您可以在子选择中进一步使用连接以获得不同的结果。Lag和RowNumber更简单,工作也很好,但它们是MS-SQL特定的,所以您需要