1

在一个 oracle 表中,每个家庭(唯一 ID)可以有几个人(唯一 ID)在一个日期范围内处于不同的关系中。我想创建一个时间线,以根据时间段的关系组合获取 FamilyType。下面给出了一个特定家庭的例子。

  P1|-----Head---------------------------------------|
           P2|--Partner--------------|
                    P3|---Child----------------------|
                              P4|---Child------------|

    |=Single=|=Couple=|=Family=======|=SingleParent==|

表有列 FamilyId、PersonId、Relationship、StartDate、EndDate

每个 | 是一个日期(没有时间部分)。数据保证在给定日期
* 总会有一个人是负责人。
* 可以有 0 个或 1 个合作伙伴。
* 可以有 0 或 n 个孩子。

规则是
* 如果只有一个 Head 则 FamilyType 为 Single
* 如果有一个 Head 和一个 Partner 则 FamilyType 为 Couple
* 如果有一个 Head 、一个 Partner 和 1 个或多个 Children 则 FamilyType 为 Family
* 如果有一个家庭类型为 SingleParent 的 Head 和 1 个或多个 Children

人们可以在任何日期加入或离开家庭。人们可以改变关系。所以以下情况是可能的

P1|----------Head--------------------|
           P2|----partner------------|---Head--------|
                    P3|---Child----------------------|
                          P4|--Child-----------------|

    |=Single=|=Couple=|=Family=======|=SingleParent==|

P1|----------Head--------------------|
           P2|----partner------------|---Head--------|
                    P3|---Child----------------------|
                          P4|--Child-----------------|
                                   p5|---Partner-----|

    |=Single=|=Couple=|=Family=======================|

如何在 Oracle 11GR2 中使用 SQL 来完成此操作(仅使用 SQL 而不是使用过程代码)。我正在尝试评估这是否最好在 SQL 或 C# 中完成。作为特定于 SQL Server 2012 的好奇答案也很好。

结果应该是包含 StartDate、EndDate 和 FamilyType 的行。

4

1 回答 1

2

你可以这样做:

with family_ranges(familyid, min_start, max_end, curr_date)
  as (select familyid, 
             min(startdate), 
             max(enddate),
             to_number(to_char(min(startdate), 'j'))
       from family
      group by familyid
      union all
      select familyid, min_start, max_end, curr_date+1
       from family_ranges
       where curr_date < to_number(to_char(max_end,'j')))
select familyid, min(curr_date) fromdate, max(curr_date) todate, state
  from (select familyid, to_date(curr_date,'j') curr_date,
               case when head = 'Y' and partner = 'Y' and child = 'Y' then 'Family'
                when head = 'Y' and partner = 'Y' then 'Couple'
                when head = 'Y'  and child = 'Y' then 'SingleParent'
                when head = 'Y' then 'Single'
               end state
          from (select f.familyid, d.curr_date, f.relationship
                  from family_ranges d
                      inner join family f
                              on f.familyid = d.familyid
                            and to_date(d.curr_date,'j') between f.startdate and f.enddate)
         pivot (
           max('Y')
           for  relationship in ('Head' as head, 'Partner' as partner, 'Child' as child)
         ))
 group by familyid, state
 order by familyid, fromdate;

用日期->朱利安原谅废话。这是为了解决 11.2.0.1-3 的错误,其中日期算术因分解子查询而失败。

虚构的子查询部分为我们提供了家庭跨越的日期列表。从那以后,我们将其重新加入家庭,以计算出那天谁在家庭中。

select f.familyid, d.curr_date, f.relationship
  from family_ranges d
      inner join family f
              on f.familyid = d.familyid
            and to_date(d.curr_date,'j') between f.startdate and f.enddate;

现在我们旋转它以获得一个简单的 Y/N 列表

SQL> with family_ranges(familyid, min_start, max_end, curr_date)
  2    as (select familyid,
  3               min(startdate),
  4               max(enddate),
  5               to_number(to_char(min(startdate), 'j'))
  6         from family
  7        group by familyid
  8        union all
  9        select familyid, min_start, max_end, curr_date+1
 10         from family_ranges
 11         where curr_date < to_number(to_char(max_end,'j')))
 12  select familyid, to_date(curr_date,'j') curr_date, head, partner, child
 13            from (select f.familyid, d.curr_date, f.relationship
 14                    from family_ranges d
 15                        inner join family f
 16                                on f.familyid = d.familyid
 17                              and to_date(d.curr_date,'j') between f.startdate and f.enddate)
 18           pivot (
 19             max('Y')
 20             for  relationship in ('Head' as head, 'Partner' as partner, 'Child' as child)
 21           );

  FAMILYID CURR_DATE H P C
---------- --------- - - -
         1 09-NOV-12 Y
         1 11-NOV-12 Y
         1 13-NOV-12 Y
         1 23-NOV-12 Y
         2 23-NOV-12 Y
         2 28-NOV-12 Y Y
         2 29-NOV-12 Y Y
         1 30-NOV-12 Y Y
         1 01-DEC-12 Y Y
         1 03-DEC-12 Y Y
         2 18-DEC-12 Y Y Y
         2 20-DEC-12 Y Y Y

那么这是一个简单的案例,可以从规则中获取所需的字符串,并通过分组来获取日期范围。

SQL> with family_ranges(familyid, min_start, max_end, curr_date)
  2    as (select familyid,
  3               min(startdate),
  4               max(enddate),
  5               to_number(to_char(min(startdate), 'j'))
  6         from family
  7        group by familyid
  8        union all
  9        select familyid, min_start, max_end, curr_date+1
 10         from family_ranges
 11         where curr_date < to_number(to_char(max_end,'j')))
 12  select familyid, min(curr_date) fromdate, max(curr_date) todate, state
 13    from (select familyid, to_date(curr_date,'j') curr_date,
 14                 case when head = 'Y' and partner = 'Y' and child = 'Y' then 'Family'
 15                  when head = 'Y' and partner = 'Y' then 'Couple'
 16                  when head = 'Y'  and child = 'Y' then 'SingleParent'
 17                  when head = 'Y' then 'Single'
 18                 end state
 19            from (select f.familyid, d.curr_date, f.relationship
 20                    from family_ranges d
 21                        inner join family f
 22                                on f.familyid = d.familyid
 23                              and to_date(d.curr_date,'j') between f.startdate and f.enddate)
 24           pivot (
 25             max('Y')
 26             for  relationship in ('Head' as head, 'Partner' as partner, 'Child' as child)
 27           ))
 28   group by familyid, state
 29   order by familyid, fromdate;

  FAMILYID FROMDATE  TODATE    STATE
---------- --------- --------- ------------
         1 05-NOV-12 24-NOV-12 Single
         1 25-NOV-12 14-DEC-12 Couple
         1 15-DEC-12 24-JAN-13 Family
         1 25-JAN-13 13-FEB-13 SingleParent
         2 05-NOV-12 24-NOV-12 Single
         2 25-NOV-12 14-DEC-12 Couple
         2 15-DEC-12 13-FEB-13 Family

小提琴:http ://sqlfiddle.com/#!4/484b5/1

于 2013-02-14T00:49:32.413 回答