【问题标题】:SQL How to combine Timestamps to show a duration?SQL 如何结合时间戳来显示持续时间?
【发布时间】:2015-03-28 01:41:33
【问题描述】:

我有以下查询,其中数据是 STORAGE_BOX 中任何给定时间的 ITEM 的位置,其中可以进一步指定项目的位置一个分隔符,这样您就可以拥有 STORAGE_BOX/SLOT/TRAY/ROW_ID。这就是我为该列执行 SUBSTRING 的原因。

我正在尝试做的事情:创建一个视图以显示特定物品在特定存储盒中的START_DATEEND_DATE

select at.primary_key as 'ITEM_ID', f.name as 'INSTITUTION', SUBSTRING(sc.location +'/',0, CHARINDEX('/', sc.location + '/'))
 as 'STORAGE_BOX', at.db_timestamp as 'TIMESTAMP' from [dbo].AUDIT_TRAIL at 

RIGHT JOIN [dbo].BIOMATERIAL bio on at.primary_key = bio.id
LEFT JOIN [dbo].FACILITY f on bio.at_facility_id = f.id
LEFT JOIN [dbo].STORAGE_CONTAINER sc on at.primary_key = sc.id

where at.table_name = 'Biomaterial' AND sc.location IS NOT NULL 

所以上述查询的以下输出

+---------+-------------+-------------+------------+
| ITEM_ID | INSTITUTION | STORAGE_BOX | TIMESTAMP  |
+---------+-------------+-------------+------------+
|       1 | Building#1  | STORAGE_0   | 2012-03-25 |
|       1 | Building#1  | STORAGE_0   | 2013-12-25 |
|       1 | Building#1  | STORAGE_1   | 2015-03-25 |
|       2 | Building#2  | STORAGE_3   | 2012-03-25 |
|       2 | Building#2  | STORAGE_4   | 2013-03-25 |
|       2 | Building#2  | STORAGE_5   | 2015-03-25 |
+---------+-------------+-------------+------------+

并将其更改为以下结果,其中 START_DATE 是新 STORAGE_BOX 的第一个时间戳,而 END_DATE 是下一个 STORAGE_BOX 的下一个时间戳,如果它仍然存在,则为当前时间戳。

我不知道如何计算上述查询中的这些字段以使其显示

+---------+-------------+-------------+------------+---------------------+
| ITEM_ID | INSTITUTION | STORAGE_BOX | START_DATE |      END_DATE       |
+---------+-------------+-------------+------------+---------------------+
|       1 | Building#1  | STORAGE_0   | 2012-03-25 | 2015-03-25          |
|       1 | Building#1  | STORAGE_1   | 2015-03-25 | {Current_TimeStamp} |
|       2 | Building#2  | STORAGE_3   | 2012-03-25 | 2013-03-25          |
|       2 | Building#2  | STORAGE_4   | 2013-03-25 | 2015-03-25          |
|       2 | Building#2  | STORAGE_5   | 2015-03-25 | {Current_TimeStamp} |
+---------+-------------+-------------+------------+---------------------+

编辑

我使用 Gordon Linoff 提供的答案创建了以下带有 sql server 2008 限制的查询

with t as (
      select at.transaction_uid,at.primary_key as BIOMATERIAL_ID, f.name as INSTITUTION,
             at.new_value as FREEZER,
             at.db_timestamp as TIMESTAMP
      from [dbo].AUDIT_TRAIL at RIGHT JOIN
           [dbo].BIOMATERIAL bio
           on at.primary_key = bio.id LEFT JOIN
           [dbo].FACILITY f
           on bio.at_facility_id = f.id 
      where at.table_name = 'Biomaterial' AND at.column_name = 'container_id.location' AND at.new_value IS NOT NULL 
     ),
     t1 as (
      select t.*,
             row_number() over (partition by BIOMATERIAL_ID, INSTITUTION,  FREEZER
                                order by timestamp) as seqnum
      from t 
        ),
        t2 as(
            select t1.*,
                ROW_NUMBER() over (partition by BIOMATERIAL_ID order by seqnum) as seqnum_b
              from t1
              where t1.seqnum = 1
            )
    SELECT a.BIOMATERIAL_ID, a.INSTITUTION, a.FREEZER, a.TIMESTAMP as START_DATE,coalesce(b.TIMESTAMP, getdate()) as END_DATE 
        FROM t2 a left join t2 b on a.BIOMATERIAL_ID = b.BIOMATERIAL_ID AND a.seqnum_b = (b.seqnum_b + 1) order by a.BIOMATERIAL_ID 

【问题讨论】:

    标签: sql timestamp subquery substring calculated-columns


    【解决方案1】:

    您可以使用窗口函数来做到这一点。首先使用row_number() 获取每个组的第一行:

    with t as (
          select at.primary_key as ITEM_ID, f.name as INSTITUTION,
                 SUBSTRING(sc.location +'/',0, CHARINDEX('/', sc.location + '/')) as STORAGE_BOX,
                 at.db_timestamp as TIMESTAMP
          from [dbo].AUDIT_TRAIL at RIGHT JOIN
               [dbo].BIOMATERIAL bio
               on at.primary_key = bio.id LEFT JOIN
               [dbo].FACILITY f
               on bio.at_facility_id = f.id LEFT JOIN 
               [dbo].STORAGE_CONTAINER sc
               on at.primary_key = sc.id
          where at.table_name = 'Biomaterial' AND sc.location IS NOT NULL
         ),
         t1 as (
          select t.*,
                 row_number() over (partition by ITEM_ID, INSTITUTION,  STORAGE_BOX
                                    order by timestamp) as seqnum
          from t
         ),
         t2 as (
          select t1.*, lead(timestamp) over (partition by item_id, institution order by timestamp) as next_timestamp
          from t1
          where seqnum = 1
         )
    select t2.ITEM_ID, t2.INSTITUTION, t2.STORAGE_BOX,
           t2.timstamp as START_DATE,
           coalesce(t2.next_timestamp, getdate()) as END_DATE
    from t2 ;
    

    第一个 CTE 是您的查询。第二个枚举每个项目、机构和存储箱的行以消除重复。这似乎是您查询的逻辑,但如果一个存储箱为同一个项目/位置使用了两次,则可能需要更复杂的逻辑。

    第三个 CTE,t2 获取下一个时间戳。最后的查询应用逻辑。

    这假设 SQL Server 2012+(根据您的语法,我假设 SQL Server)。您可以在早期版本中使用outer apply 执行类似的操作。

    【讨论】:

    • 遗憾的是,我使用的 SQL Server 2008 没有 LEAD 功能
    猜你喜欢
    • 2021-11-04
    • 2021-01-02
    • 1970-01-01
    • 2015-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多