【问题标题】:sql turn dates of adding and removing into date rangessql将添加和删除日期转换为日期范围
【发布时间】:2009-10-01 15:35:08
【问题描述】:

我正在使用一个名为 CELCAT 的时间表应用程序,并试图提取一些关于何时应标记学生以进行报告的数据...这似乎非常困难,因为在登记册上添加和删除学生的方式是结构化的见下文:

studentid   eventid     fromdatetime                addition    removal
25149       25145       2009-09-12 10:30:00.000     Y           NULL
25149       25145       2009-09-12 10:30:00.000     NULL        Y
25149       25145       2009-09-12 10:30:00.000     Y           NULL
25150       23013       2009-09-08 09:00:00.000     Y           NULL
25150       23554       2009-09-07 09:00:00.000     Y           NULL
25150       25145       2009-09-12 10:30:00.000     Y           NULL
25150       25145       2009-07-27 00:00:00.000     NULL        Y
25150       25145       2009-09-12 10:30:00.000     Y           NULL
25150       25145       2009-09-12 10:30:00.000     NULL        Y
25150       25145       2009-09-12 10:30:00.000     Y           NULL
25150       25148       2009-09-12 15:00:00.000     Y           NULL
25151       25145       2009-09-12 10:30:00.000     Y           NULL
25151       25145       2009-10-10 00:00:00.000     NULL        Y
25152       25145       2009-09-19 10:30:00.000     Y           NULL
25152       25145       2009-07-27 00:00:00.000     NULL        Y

因此,添加一个学生意味着他们应该从该日期起在登记册中进行标记(登记册是每周重复发生的事件,具有自己的周概况,不过我可以处理这方面的事情)。删除意味着学生不需要在此日期之后被标记,但是可能会添加、删除学生,然后在以后的一周内重新添加。

我认为能让我朝着正确方向前进的方法是获得一个结构表

studentid    eventid    fromdate                      todate
25149          25145    2009-09-12 10:30:00.000       2009-09-28 10:30:00.000     
25149          25145    2009-10-13 10:30:00.000       2009-10-24 10:30:00.000 

任何想法如何做到这一点?或者更好的建议?我想它会涉及到一些游标的使用,除非有人有一个很棒的解决方案。表格由 CELCAT 设计,不能修改。

哦,是的,它是 sql server 2005。

EDIT by KM,这里有一些用于测试解决方案的代码:

DECLARE @YourTable table (studentid int
                         ,eventid int
                         ,fromdatetime datetime
                         ,addition char(1) 
                         ,removal char(1)
                         )

SET NOCOUNT ON
INSERT INTO @YourTable VALUES (25149,25145,'2009-09-12 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25149,25145,'2009-09-12 10:30:00.000', NULL,'Y')
INSERT INTO @YourTable VALUES (25149,25145,'2009-09-12 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25150,23013,'2009-09-08 09:00:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25150,23554,'2009-09-07 09:00:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25150,25145,'2009-09-12 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25150,25145,'2009-07-27 00:00:00.000', NULL,'Y')
INSERT INTO @YourTable VALUES (25150,25145,'2009-09-12 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25150,25145,'2009-09-12 10:30:00.000', NULL,'Y')
INSERT INTO @YourTable VALUES (25150,25145,'2009-09-12 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25150,25148,'2009-09-12 15:00:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25151,25145,'2009-09-12 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25151,25145,'2009-10-10 00:00:00.000', NULL,'Y')
INSERT INTO @YourTable VALUES (25152,25145,'2009-09-19 10:30:00.000','Y'  ,NULL)
INSERT INTO @YourTable VALUES (25152,25145,'2009-07-27 00:00:00.000', NULL,'Y')
SET NOCOUNT OFF

【问题讨论】:

  • 如何从给定的样本数据中获取这两个日期范围行?当您想要的“答案”与给定的样本数据不匹配时,很难为您进行查询。
  • 此表/视图中是否有另一列指示添加记录时的时间戳或至少增量标识符?如果不是,那么很难为 ID=25149 的学生制定逻辑,因为他在同一事件中添加和删除了 3 次,但不清楚首先做了什么。
  • 如果您指出您希望得到什么“最终”结果,而不仅仅是“..正确的方向..”,这也会有所帮助。谢谢
  • 您如何在提出问题的同时向那些试图提供帮助的人提供零反馈?

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

我不确定您尝试获取的查询以及日期范围将如何提供帮助。

但是,您可以保留当前表,它就像一个日志。只需添加一个保持当前状态的汇总表。插入旧表并更新新表。您可以查询新的以判断是否 IN/OUT,并使用旧的进行更详细的分析。

【讨论】:

    【解决方案2】:

    我不太确定您需要如何处理数据,但这里是如何将数据转换为您想要的格式的方法。

    SELECT studentid, eventid, fromdatetime as fromdate, 
        (SELECT TOP 1 fromdatetime FROM table 
        WHERE studentid = t1.studentid 
            AND eventid = t1.eventid 
            AND removal = 'Y' AND fromdatetime > t1.fromdatetime
        ) AS todate
    FROM table t1
    WHERE addition = 'Y'
    

    此查询将以您要求的格式生成数据:

    studentid    eventid   fromdate                      todate
    25149        25145     2009-09-12 10:30:00.000       2009-09-28 10:30:00.000
    25149        25145     2009-10-13 10:30:00.000       2009-10-24 10:30:00.000 
    

    对于大量数据,此查询可能效率低下,因此我真的希望您的表有一个已编入索引的标识行。如果是这样,请将AND fromdatetime > t1.fromdatetime 替换为AND id > t1.id。这应该会使子查询更有效率。

    【讨论】:

    • 我试过这个查询,但它不起作用。我将使用表定义编辑原始问题并插入以填充示例数据。从那里你所要做的就是用“FROM @YourTable”替换两个“FROM table”并使用我在原始问题中输入的代码。
    • 我看过这个,查询确实按照我认为的方式工作,但目前的问题是数据。可能我对数据的结构有误解,但是在上面的示例数据中,有插入后删除、同一天多次插入、同一天插入和删除。也许 OP 可以准确解释数据代表什么,以及上面发布的示例是实时数据还是模型。
    【解决方案3】:

    我认为示例数据有问题 前 3 条记录

    25149 25145 2009-09-12 10:30:00.000 是 NULL 25149 25145 2009-09-12 10:30:00.000 空是 25149 25145 2009-09-12 10:30:00.000 是 NULL 基本上他们说,学生同时被添加/删除并再次添加。 但是,请记住,选择订单时不能保证。怎么知道学生不是先被删除然后又被添加了两次? 问题要求行
    25149 25145 2009-10-13 10:30:00.000 2009-10-24 10:30:00.000
    在输出中,但数据中没有“2009-10-13”值。



    然后这三个:

    25150 25145 2009-09-12 10:30:00.000 是 NULL
    25150 25145 2009-07-27 00:00:00.000 空是
    25150 25145 2009-09-12 10:30:00.000 是 NULL
    正是我上面描述的假设场景——从日期来看,学生先被删除,然后被添加两次!

    【讨论】:

      【解决方案4】:

      一种简单的方法是创建一个标量函数,该函数为 studentid 和 eventid 返回一个位,指示该学生是进还是出:

      create function Event_IsStudentIn(@eventID int, @studentID int)
      returns bit as
      begin
          declare @in bit
      
          set @in = 0
      
          select 
           @in = case when addition = 'Y' then 1 else 0 end
          from [table]
          where eventid = @eventID and studentid = @studentID
          order by fromdatetime desc                  
      
          return @in
      end
      

      但是,将来您可能希望重组该数据。

      【讨论】:

      • 我不明白这是如何解决的,可能我的问题表述得不够好。
      猜你喜欢
      • 2013-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-18
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      • 1970-01-01
      相关资源
      最近更新 更多