このディレクトリの索引
#  出題場所 :: http://toro.2ch.net/test/read.cgi/db/1371476534/541
#  質問です教えてください 
#   
#  データベース = access 
#  テーブル名   = T_DATA 
#   
#  SQLで取得したい結果は、KEYごとに日数を取得したいのですが 
#  重複する日数はカウントから除外したいです。 
#  どんなSQLを書けばいいですか? 
#   
#   ・キーは、日数=5日 
#   ・キーは、日数=1日 
#   
#  ---------------------------------- 
#  キー,     開始日,     終了日 
#  ---------------------------------- 
#    1, 2014/01/01, 2014/01/01 |→ 日数=1日 
#    1, 2014/01/02, 2014/01/02 |→ 日数=1日 
#    1, 2014/01/02, 2014/01/02 |→ 日数=0日(重複) 
#    1, 2014/01/03, 2014/01/03  |→ 日数=1日 
#    1, 2014/01/04, 2014/01/05  |→ 日数=2日、合計=5日 
#  --- 
#    2, 2014/01/01, 2014/01/01  |→ 日数=1日 
#    2, 2014/01/01, 2014/01/01  |→ 日数=0日(重複)、合計=1日 
#   
#  ↓これだと重複がカウントされてしまいます。 
#  SELECT 
#    キー 
#   ,SUM(DATEDIFF('d', 開始日, 終了日)+1) AS 日数 
#  FROM 
#   T_DATA 
#  GROUP BY 
#    キー 
# 

'データベース = access 
テーブル名   = T_DATA 
 
SQLで取得したい結果は、KEYごとに日数を取得したいのですが 
重複する日数はカウントから除外したいです。'(_キーごとの日数) :-
        setof(_キー,[_キー,_開始日,_終了日] ^ 'T_DATA'(_キー,_開始日,_終了日),_キーならび),
        findall([_キー,_日数],(
                    member(_キー,_キーならび),
                    キーの日数を得る(_キー,_日数)),
                _キーごとの日数).


キーの日数を得る(_キー,_日数) :-
        findall(_日,(
                    'T_DATA'(_キー,_開始日,_終了日),
                    整数構造に変換(_開始日,_終了日,_開始日整数構造,_終了日整数構造),
                    範囲の日を引出す(_開始日整数構造,_終了日整数構造,_日)),
                L1),
        重複日を取り除いた日数(L1,_日数).

整数構造に変換(_開始日,_終了日,_開始日整数構造,_終了日整数構造) :-
        read_term_from_atom(_開始日,_開始日整数構造),
        read_term_from_atom(_終了日,_終了日整数構造).

範囲の日を引出す(_終了日,_終了日,_終了日) :- !.
範囲の日を引出す(_日,_終了日,_日).
範囲の日を引出す(_日_1,_終了日,_日) :-
        翌日(_日_1,_翌日),
        範囲の日を引出す(_翌日,_終了日,_日).

翌日(_年/12/_31,_翌年/1/1) :-
        _翌年 is _年 + 1,!.
翌日(_年/_月/_日,_年/_翌月/1) :-
        月末日(_年/_月/_日),
        _翌月 is _月 + 1,!.
翌日(_年/_月/_日,_年/_月/_翌日の日) :-
        _翌日の日 is _日 + 1,!.

月末日(_年/2/29) :-
        うるう年(_年),!.
月末日(_年/2/28) :-
        \+(うるう年(_年)),!.
月末日(_年/_月/30) :-
        member(_月,[4,6,9,11]),!.
月末日(_年/_月/31) :-
        member(_月,[1,3,5,7,8,10,12]).

うるう年(_年) :-
    0 is _年 mod 400,!.
うるう年(_年) :-
    0 is _年 mod 100,!,
    fail.
うるう年(_年) :-
    0 is _年 mod 4,!.
うるう年(_年) :-
    \+(0 is _年 mod 4),
    fail.

重複日を取り除いた日数(L1,_日数) :-
        sort(L1,L2),
        length(L2,_日数).