【问题标题】:Get and filter dates SQL [closed]获取和过滤日期 SQL [关闭]
【发布时间】:2020-10-13 22:14:16
【问题描述】:

我有这张没有pk的表

| Peo  | Pos | DATE_BEGIN | DATE_END   | XXXX |
+------+-----+------------+------------+------+
| 9302 | 8   | 2017-10-02 | 2017-12-31 | NULL |
| 9302 | 8   | 2018-01-01 | 2018-01-01 | NULL |
| 9302 | 8   | 2018-01-02 | 2018-05-31 | NULL |
| 9302 | 8   | 2018-06-01 | 9999-12-31 | NULL |

并且我想将 Pos 8 中的时间从较旧的 DATE_BEGIN 传递到较新的 Date_END,如果未定义,则可能是 9999-12-31,在这种情况下将是实际日期。此表为 2017-10-02 至 9999-12-31(2020/06/23,实际日期)。

一个问题是,对于下面的表格,它应该只获得最后一行,因为该人在 Pos 中的总时间是因为它被更改了。所以将是 (2018-06-01) - (9999-12-31 - 实际日期)

| Peo  | Pos | DATE_BEGIN | DATE_END   | XXXX |
+------+-----+------------+------------+------+
| 9302 | 8   | 2017-10-02 | 2017-12-31 | NULL |
| 9302 | 8   | 2018-01-01 | 2018-01-01 | NULL |
| 9302 | 7   | 2018-01-02 | 2018-05-31 | NULL |
| 9302 | 8   | 2018-06-01 | 9999-12-31 | NULL |

【问题讨论】:

  • "未定义时可能是 9999-12-31" - 所以,有人不知道 NULL 在 SQL 中的含义,现在您必须处理损坏的数据模型?我以为我们在 2000 年就摆脱了它。

标签: sql-server date select where-clause gaps-and-islands


【解决方案1】:

这是一个典型的间隙和孤岛问题。您正在寻找带有pos = 8 的最终行序列(每个peo)。

因此,对于每个peo,您需要按日期倒数,以查找序列中的中断。这样分组后,您将只保留第一个这样的分组,然后聚合:

with data as (
    select *,
        sum(case when pos = 8 then 0 else 1 end)
            over (partition by peo order by date_begin desc) as brk
    from TblX t
    -- this is unnecessary if the latest row is always pos = 8
    where date_begin <= (
        select max(t2.date_begin) from TblX t2
        where t2.peo = t.peo and t2.pos = 8
    )
)
select
    peo,
    min(date_begin) as date_begin,
    case max(date_end)
            when '9999-12-31' then cast(getdate() as date)
            else max(date_end) end as date_end,
    datediff(day,
        min(date_begin),
        case max(date_end)
            when '9999-12-31' then cast(getdate() as date)
            else max(date_end) end
    ) as days_difference
from data
where brk = 0
group by peo;

这种方法适用于返回的不仅仅是最近的分组。 GMB 的答案在其他方面非常相似。

【讨论】:

    【解决方案2】:

    我认为你想要:

    select
        peo,
        datediff(
            day, 
            min(date_begin), 
            case when max(date_end) = '9999-12-31' then cast(getdate() as date) else max(date_end) end
        ) days
    from mytable t
    where not exists (
        select 1 
        from mytable t1 
        where 
            t1.peo = t.peo 
            and t1.date_begin > t.date_end 
            and t1.pos <> 8
    )
    group by peo
    

    对于每个peowhere 子句过滤表的最后一系列记录,其pos8。然后查询聚合peo,并计算最小date_begin和最大date_end之间的差(如果date_end'9999-12-31',我们使用当前日期代替)。

    【讨论】:

    • 我更改了 pos 比较以包括其他职位。这解决了我的问题,将获得当前用户位置的天数。不存在的地方(从 mytable t1 中选择 1 where t1.peo = t.peo and t1.date_begin > t.date_end and t1.pos t.pos )按 peo 分组
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多