在表格中添加值并更改相应的日期范围

时间:2013-02-06 06:05:53

标签: sql-server sql-server-2008-r2

这是我的先决条件。

user_id  | module_start_date | module_end_date | loading
 6       | 01-01-2013        | 31-01-2013      | 0.4
 6       | 16-01-2013        | 31-01-2013      | 0.2
 6       | 01-03-2013        | 15-03-2013      | 0.7
 6       | 30-01-2013        | 30-01-2013      | 0.5

我必须添加加载并更改日期范围,如图所示。 使用相同的start_date和end_date可以在上述条件中添加面临的问题。

注意: - 可能有多个用户。

user_id   |  module_start_date| module_end_date | loading
  6       | 01-01-2013        | 15-01-2013      | 0.4
  6       | 16-01-2013        | 29-01-2013      | 0.6
  6       | 30-01-2013        | 30-01-2013      | 1.1
  6       | 31-01-2013        | 31-01-2013      | 0.6
  6       | 01-03-2013        | 15-03-2013      | 0.7

1 个答案:

答案 0 :(得分:0)

如果您的结束日期是独家的,这将会更容易一些。不过,这是一个计划:

  1. 暂时增加每个范围内的结束日期,使其成为独家日期。

  2. 将所有开始日期和结束日期放入一个列表中,仅提取不同的日期。

  3. 将每两个日期彼此相邻以形成新范围。

  4. 将新范围列表加入到结束日期增加的列表中,按新范围分组并获取loading的总计。

  5. 将新范围转换为原始"全包"通过将每个结束日期减1来格式化。

  6. 这是上述计划的实施:

    WITH converted AS (
      -- #1
      SELECT
        user_id,
        module_start_date,
        module_end_date = DATEADD(DAY, 1, module_end_date),
        loading
      FROM atable
    ),
    datesranked AS (
      -- #2
      SELECT
        c.user_id,
        x.date,
        rnk = ROW_NUMBER() OVER (PARTITION BY c.user_id ORDER BY x.date)
      FROM converted AS c
      CROSS APPLY (
        VALUES (c.module_start_date), (c.module_end_date)
      ) AS x (date)
      GROUP BY
        c.user_id,
        x.date
    ),
    newranges AS (
      -- #3
      SELECT
        d1.user_id,
        module_start_date = d1.date,
        module_end_date   = d2.date
      FROM
      datesranked AS d1
      INNER JOIN datesranked AS d2
        ON d1.user_id = d2.user_id
        AND d1.rnk = d2.rnk - 1
    ),
    totals AS (
      -- #4 & #5
      SELECT
        new.user_id,
        new.module_start_date,
        module_end_date = DATEADD(DAY, -1, new.module_end_date),
        loading = SUM(old.loading)
      FROM newranges AS new
      INNER JOIN converted AS old
        ON new.user_id = old.user_id
        AND new.module_end_date > old.module_start_date
        AND new.module_start_date < old.module_end_date
      GROUP BY
        new.user_id,
        new.module_start_date,
        new.module_end_date
    )
    SELECT *
    FROM totals
    ;
    

    上面的实现是SQL Fiddle demo