1

各家族 (一意の ID) のオラクル テーブルでは、日付範囲に対して異なる関係にある複数の人 (一意の ID) を持つことができます。期間の関係の組み合わせに基づいて FamilyType を取得するためにタイムラインを作成したいと考えています。特定のファミリの例を以下に示します。

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

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

テーブルには、FamilyId、PersonId、Relationship、StartDate、EndDate の列があります

それぞれ | 日付です (時刻部分なし)。
データは、特定の日付* に常に 1 人の人物がヘッドであることを保証します。
※パートナーは0人でも1人でも構いません。
* 0 または n の子が存在する可能性があります。

ルールは次のとおりです *
頭だけの場合、FamilyType は独身です
* 頭とパートナーがいる場合、FamilyType は夫婦です
* 頭とパートナーと 1 人以上の子供がいる場合、FamilyType は家族です
* ある場合は、FamilyType は家族ですFamilyType が SingleParent である頭と 1 人以上の子

家族はいつでも参加または脱退できます。そして、人は人間関係を変えることができます。したがって、次のシナリオが可能です

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のバグを回避することです。

fatoredサブクエリ部分は、ファミリがまたがる日付のリストを取得します。それから私たちはそれを家族に戻し、その日に家族の中にいた人を見つけ出します。

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 に答える