0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プリザンター内部で動くSQL文を調べてみる[第5回:ガントチャート編]

0
Posted at

はじめに

第 4 回 ではカレンダービューの日付範囲クエリを解説しました。
本記事(第 5 回)では ガントチャート に絞り、GanttUtilities.Where() と GanttLimit の実装を解説します。

バージョン 1.5.2.0 を対象にしています

回 タイトル
第 1 回 アーキテクチャ編 ── SQL を組み立てる仕組みの全体像
第 2 回 一覧編 ── フィルタとソートの WHERE・ORDER BY
第 3 回 編集編 ── SELECT・INSERT・UPDATE の実装
第 4 回 カレンダー編 ── 日付範囲クエリの実装
第 5 回(本記事) ガントチャート編 ── GanttUtilities.Where() と GanttLimit
第 6 回 バーンダウンチャート編 ── 現在 + 履歴 UNION クエリ
第 7 回 時系列チャート編 ── HorizontalAxis と NormalAndHistory
第 8 回 カンバン編 ── KambanLimit・全件取得・カード移動
第 9 回 クロス集計編 ── GROUP BY と日付軸グループ化式
第 10 回 画像ライブラリ編 ── Binaries INNER JOIN クエリ
第 11 回 分析チャート編 ── 分析パーツごとの現在+履歴 SQL

処理フロー

GET /items/{siteId}/gantt
 └─ IssueUtilities.Gantt()                         ← L9607 IssueUtilities.cs
     ├─ GanttDataRows()                            ← L9788 IssueUtilities.cs
     │   └─ Rds.SelectIssues(進捗列多数,
     │           WHERE: GanttUtilities.Where() + フィルタ)
     │       ① SELECT(表示期間内レコード・COUNT SQL なし)
     └─ dataRows.Count() <= Parameters.General.GanttLimit
         件数チェック(SELECT COUNT は発行しない)

ガントチャートビューの SQL

GanttDataRows メソッド

ガントチャートのデータ取得は IssueUtilities.GanttDataRows() が担います。

Models/Issues/IssueUtilities.cs
private static EnumerableRowCollection<DataRow> GanttDataRows(
    Context context, SiteSettings ss, View view, Column groupBy, Column sortBy)
{
    // ① GanttUtilities.Where() を先に設定し、画面フィルタを追加
    var where = view.Where(
        context, ss,
        where: Libraries.ViewModes.GanttUtilities.Where(context, ss));

    // ② ガント期間パラメータの設定
    var param = view.Param(context, ss);
    var start = view.GanttStartDate.ToDateTime().ToUniversal(context);
    var end   = start.AddDays(view.GanttPeriod.ToInt()).AddMilliseconds(-3);
    param.Add(new SqlParam() { VariableName = "Start", Value = start, NoCount = true });
    param.Add(new SqlParam() { VariableName = "End",   Value = end,   NoCount = true });

    // ③ SELECT(ガント表示に必要な列)
    return Repository.ExecuteTable(context, statements: Rds.SelectIssues(
        column: Rds.IssuesTitleColumn(context, ss)
            .IssueId()
            .WorkValue()
            .StartTime()
            .CompletionTime()
            .ProgressRate()
            .Status()
            .Owner()
            .Updator()
            .CreatedTime()
            .UpdatedTime()
            .ItemTitle(ss.ReferenceType)
            .Add(context, column: groupBy, function: Sqls.Functions.SingleColumn)
            .Add(context, column: sortBy,  function: Sqls.Functions.SingleColumn),
        join: ss.Join(context, join: where),
        where: where,
        param: param))
            .AsEnumerable();
}

ガントチャートの日付範囲条件

ガントチャートでは GanttUtilities.Where() で日付範囲条件が生成されます。カレンダーと同様の「3 パターン OR」が使われています。

WHERE (
    "Issues"."StartTime" between @Start and @End
    OR "Issues"."CompletionTime" between @Start and @End
    OR "Issues"."StartTime" <= @Start AND "Issues"."CompletionTime" >= @End
)
AND ...(画面フィルタ条件・権限条件)

カレンダーとの違いは パラメータ名(Begin/End → Start/End)と、表示期間の計算方法 です。

GanttUtilities.Where() の実装

カレンダーの CalendarDataRows() が生列名を直接使うのに対し、GanttUtilities.Where() は Def.Sql.StartTimeColumn・CompletionTimeSql() という定義ファイル参照の SQL 式を使います。これはプリザンターが CompletionTime に「業務日換算」の補正を加えられる設計になっているためです。

Libraries/ViewModes/GanttUtilities.cs
public static SqlWhereCollection Where(Context context, SiteSettings ss)
{
    // 3パターン OR:カレンダーと同じ構造
    return Rds.IssuesWhere().Add(or: Rds.IssuesWhere()
        // パターン①:期間全体を包む(StartTime <= @Start AND CompletionTime >= @End)
        .Add(raw: "(({0}) <= @Start and {1} >= @End)".Params(
            Def.Sql.StartTimeColumn,
            CompletionTimeSql(context: context, ss: ss)))
        // パターン②:開始日が期間内(StartTime between @Start and @End)
        .Add(raw: "({0}) between @Start and @End".Params(
            Def.Sql.StartTimeColumn))
        // パターン③:終了日が期間内(CompletionTime between @Start and @End)
        .Add(raw: "({0}) between @Start and @End".Params(
            CompletionTimeSql(context: context, ss: ss))));
}

// CompletionTime に業務日換算の補正を加えた SQL 式を生成
private static string CompletionTimeSql(Context context, SiteSettings ss)
{
    return Def.Sql.CompletionTimeColumn.Replace(
        "#DifferenceOfDates#",
        TimeExtensions.DifferenceOfDates(
            ss.GetColumn(context: context, columnName: "CompletionTime")?
                .EditorFormat, minus: true).ToString());
}

生成される WHERE 句のイメージ(業務日換算なしの場合):

WHERE (
    "Issues"."StartTime" <= @Start AND "Issues"."CompletionTime" >= @End
    OR "Issues"."StartTime" between @Start and @End
    OR "Issues"."CompletionTime" between @Start and @End
)
AND ...(画面フィルタ・権限条件)

ガントチャートの表示期間

ガントチャートの表示期間は画面設定の GanttStartDate(開始日)と GanttPeriod(表示日数)から計算されます。

var start = view.GanttStartDate.ToDateTime().ToUniversal(context);
var end   = start.AddDays(view.GanttPeriod.ToInt()).AddMilliseconds(-3);

AddMilliseconds(-3) は「最終日の 00:00:00 の直前まで」を表し、最終日そのものを取得対象に含めるための処理です。

ガントチャートの SELECT 句

カレンダーよりも多くの列を取得します。進捗バーの描画やアサイン表示に必要な情報が含まれます。

列 用途
IssueId 一意識別子
WorkValue 工数(バーの長さに使用)
StartTime ガントバーの開始位置
CompletionTime ガントバーの終了位置
ProgressRate 進捗率(バー内の塗りつぶし)
Status ステータス色
Owner 担当者表示
Updator 更新者
CreatedTime / UpdatedTime 作成日時・更新日時
グループ列 グループ分けに使用
ソート列 グループ内のソートに使用

ORDER BY はカレンダーと同様に付与されません。ガントチャート上の配置はサーバー返却後にクライアント側で処理されます。

カレンダーとガントチャートの比較

項目 カレンダー ガントチャート
データ取得メソッド CalendarDataRows() GanttDataRows()
日付範囲パラメータ @Begin / @End @Start / @End
日付範囲の種類 月 / 週 / 日 任意の開始日 + 表示日数
FROM/TO 列 設定可能(TO は省略可) StartTime / CompletionTime 固定
ORDER BY なし(クライアントで処理) なし(クライアントで処理)
取得する主な列 Id・Status・From・To・Title Id・WorkValue・StartTime・CompletionTime・ProgressRate・Status

まとめ

本記事では、ガントチャートの SQL を解説しました。

  • ガントチャート:GanttDataRows() が同様の日付範囲条件を使い、進捗バー描画に必要な列(WorkValue・ProgressRate など)を取得する

第 6 回では、バーンダウンチャートの現在 + 履歴 UNION クエリを解説します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?