「rex0220 kSQL アクションプラグイン」の実践編です。
売上 10 年分 10 万件を年別・都道府県別に集計して、kSQL Dashboard Pro で見る、という事例をひと通りやります。開発環境で実際に作って測った数字をそのまま載せます。
シリーズ: 概要 / ① 詳細画面 / ② 一覧 / ③ 集計 / ④ 運用 / ⑤ 事例(この記事) / ⑥ イベント / ⑦ オーサリング / ⑧ 請求データ / ⑨ 締めの画面 / ⑩ どこに出すか / ⑪ 多言語 / ⑫ オーサリング改善
ダッシュボードが作れなくなる日
Dashboard Pro の取得件数の上限は、ペインごとに 500〜50,000 件です(既定は 10,000 件)。売上アプリにそのままダッシュボードを置くと、こうなります。
| 見たいもの | 読む件数 | Dashboard Pro 単体 |
|---|---|---|
| 今年の都道府県別 | 約 9,400 件 | 既定(10,000)でぎりぎり足りる |
| 5 年分の推移 | 約 4.7 万件 | 上限を 50,000 に上げれば届く |
| 10 年分の推移 | 約 9.4 万件 | 上限を上げても届かない |
1 年だけ見るうちは何も困りません。年が増えて「10 年の推移を 1 枚で見たい」と言われた日に、上限に当たります。
件数より先に効くのは API
そしてもう 1 つ、件数の上限より先に効いてくるものがあります。ダッシュボードは複数の人が何回も開くので、そのたびに kintone の API を使います(約 500 件 = 1 リクエスト)。
今回のダッシュボード(4 ペイン)を開いたときの通信を実際に数えました。
| 回数 | |
|---|---|
records.json(レコードの取得) |
3 回 |
app/form/fields.json(項目の定義) |
1 回 |
| 1 回開くと合計 | 4 回 |
ペインは 4 つなのに取得は 3 回です。同じ問い合わせになるペインは 1 本にまとまります(棒と横棒は、どちらも「470 行の 年・都道府県・売上」を読むので 1 回で済んでいる)。
これを、集計せずに売上アプリを直接見る場合と比べます。問い合わせの数は同じ 3 本なので、1 本あたり「件数 ÷ 500」回になります。
| ダッシュボードが見るもの | 1 回開くと | 10 人が 1 日 10 回開くと |
|---|---|---|
| 10 年分 9.4 万件を直接 | そもそも上限で不可 | — |
| 1 年分 9,400 件を直接 | 約 57 回(19 × 3 本) | 約 5,700 回 |
| 集計した 470 行 | 4 回(実測) | 400 回 |
kintone の 1 アプリ 1 日のリクエスト数には上限があります。見るだけで 1 日 5,700 回使う画面は、それだけで窮屈です。
Dashboard Pro 側にも手当てはあります。表示中のタブだけ集計する、一度開いたタブは往復しても再実行しない、折りたたみ中は止まる、など。上の数字は「画面を開いた回数」で数えたもので、同じ画面を眺め続ける分には増えません。
考え方:上限に当てない
ここで「上限を 50,000 まで上げる」方向に行くと、余裕のない設計になります。データは増え続けるので、いつかまた当たります。
やることは逆で、ダッシュボードに読ませる件数そのものを減らします。
売上 94,000 件 --(kSQL アクションで事前集計)--> 集計 470 行 --> ダッシュボード
10 年 × 47 都道府県 = 470 行。これならどのペインも一瞬で、470 行は 500 件に収まるので取得は問い合わせ 1 本につき 1 回。4 ペインのダッシュボード全体でも 4 回(上の実測)です。
アプリは 2 つ
| アプリ | 項目 |
|---|---|
| 売上 | 売上日 / 年(数値)/ 都道府県 / 金額 / 商品区分。約 9.4 万件 |
| 年別都道府県別集計 | 集計キー(文字列1行・値の重複を禁止)/ 年 / 都道府県 / 件数 / 売上 / 集計日時 |
ここで 2 つ、つまずきやすいところがあります。
複合キーは「連結した文字列」で作る
集計の単位は「年 × 都道府県」ですが、kintone に複合キーはありません。UPSERT のキーには値の重複を禁止した項目が 1 つ要るので、2026-東京都 のように連結した文字列の項目を作って、そこに重複禁止を付けます。
キーには集計の単位をすべて入れます。あとで月単位に細かくするなら、キーも 2026-06-東京都 のように「年月 × 都道府県」に変えます。2026-東京都 のままだと、6 月を集計した結果がその年の行を上書きしてしまいます。
集計の軸は、元のアプリに持たせる
売上日から年を取り出して絞ることもできますが、年を数値の項目として売上アプリに持たせるほうが速いです。WHERE 年 = @year なら kintone の絞り込みがそのまま効きます。
アクションは 2 本だけ
集計アプリの一覧パネルにボタンを 2 つ置きます。
| 読む | 書く | 使いどころ | |
|---|---|---|---|
| この年を集計し直す(年を選ぶ) | 約 9,400 件 | 47 行 | 過去の年を直すとき・導入のとき |
| 今年を集計し直す(ボタン 1 つ) | 約 9,400 件 | 47 行 | 日々これを押す |
SQL は 2 本とも同じです。
-- @ksql dialect: 1
DECLARE @year = '';
DECLARE @now = '';
UPSERT INTO LAPP_集計 (集計キー, 年, 都道府県, 件数, 売上, 集計日時)
SELECT CONCAT(@year, '-', 都道府県) AS 集計キー,
@year AS 年,
都道府県,
COUNT(*) AS 件数,
SUM(金額) AS 売上,
@now AS 集計日時
FROM LAPP_売上
WHERE 年 = @year
GROUP BY 都道府県
ON DUPLICATE (集計キー);
違うのは @year の入れ方だけです。
- 「この年を集計し直す」は入力項目(年の選択肢を 10 年分)
- 「今年を集計し直す」は計算式
DATE_FORMAT("TODAY", "YYYY")
SQL で引っかかったところ
-
NOW()はSELECTの列には書けません(UPDATE … SET 集計日時 = NOW()なら書けます)。1 文で済ませたいので、集計日時も計算式のパラメーターにしました(DATE_FORMAT("TODAY", "YYYY-MM-DDTHH:mm:ssZ")) -
SELECTの列にパラメーターを置くときはASの別名が要ります(@year AS 年) -
CONCAT(@year, '-', 都道府県)は通ります
消えた都道府県を 0 にする
上の UPSERT には GROUP BY があるので、元が 0 件のグループは 1 行も書きません。ある年から都道府県が丸ごと消えると、集計アプリには前回の値が残ったままになり、10 年の合計が実際より多く出ます。
消してから入れ直す(DELETE FROM LAPP_集計 WHERE 年 = @year; → INSERT … SELECT)手もありますが、2 文なので消したあとで失敗するとその年が空になります。消さずに済ませるなら、0 の行を UNION ALL で足してから集計します。
-- @ksql dialect: 1
DECLARE @year = '';
DECLARE @now = '';
CREATE TEMP TABLE #t AS
SELECT 都道府県, COUNT(*) AS 件数, SUM(金額) AS 売上
FROM LAPP_売上 WHERE 年 = @year GROUP BY 都道府県
UNION ALL
SELECT 都道府県, 0 AS 件数, 0 AS 売上
FROM LAPP_集計 WHERE 年 = @year;
UPSERT INTO LAPP_集計 (集計キー, 年, 都道府県, 件数, 売上, 集計日時)
SELECT CONCAT(@year, '-', 都道府県) AS 集計キー, @year AS 年, 都道府県,
SUM(件数) AS 件数, SUM(売上) AS 売上, @now AS 集計日時
FROM #t GROUP BY 都道府県
ON DUPLICATE (集計キー);
下側は、前回書いた行から作った0 の控えです。売上が残っている都道府県は上側の値がそのまま通り(0 を足しても変わらない)、消えた都道府県は下側だけが残って 0 で更新されます。消す文が無いので、途中で失敗しても空の年にはなりません。
試しに、売上が 1 件も無い都道府県の行を集計アプリに 1 つ置いてから動かしてみました。確認の画面は「レコードを 48 件 更新します」(47 都道府県 + その 1 件)になり、7.0 秒で完了。売上が残っている都道府県の値はそのままで、置いた 1 件だけが 0 件 / 0 円になりました。
書くときに気をつけるところ:
- 上側は
COUNT(*)、まとめるときはSUM(件数)です。#tをCOUNT(*)で数えると 0 の行まで数えてしまいます -
FROM (SELECT … UNION ALL …)の入れ子(導出表)は書けません。WITHは書けますが、後ろに続けられるのはSELECTだけで、UPSERTの直前には置けません。UNION ALLは一時テーブルに受ける形にします(CREATE TEMP TABLE #t AS WITH … SELECT … UNION ALL …も通ります) - 一時テーブルの上限は、貯まった行数ではなく読んだ行数で見ます。1 年 9,400 件なら 9,400 件として数えるので、既定(10,000)で足りますが、読み取りの上限と同じ余裕しかありません
- 0 の控えを読むぶん、API が 1 回増えます(23 回 → 24 回。実行ログの実測)
連続した軸(日・月・年)なら、系列を作って左結合する
都道府県のような飛び飛びのキーには上の形(0 の控え)が要りますが、日・月・年のように連続している軸なら、軸そのものを GENERATE_SERIES で作って LEFT JOIN するほうが素直です。前回書いた行に頼りません。
鳥取県の 2026 年 11 月で試します。この月に売上があるのは 3 日だけ(レコードは 4 件)です。
WITH 日付系列 AS (GENERATE_SERIES('2026-11-01', '2026-11-30') AS 日付),
日別 AS (SELECT 売上日, SUM(金額) AS 合計
FROM LAPP_売上
WHERE 都道府県 = '鳥取県' AND 売上日 >= '2026-11-01' AND 売上日 <= '2026-11-30'
GROUP BY 売上日)
SELECT s.日付, CASE WHEN d.合計 = '' THEN 0 ELSE d.合計 END AS 合計
FROM 日付系列 AS s
LEFT JOIN 日別 AS d ON s.日付 = d.売上日
ORDER BY s.日付;
4 件のレコードから 30 行が出ます。
2026-11-01 0
2026-11-02 152484
2026-11-03 0 ← 11-09 まで 0 が並ぶ
2026-11-10 112119
2026-11-11 0
2026-11-12 269483 ← この日は 2 件あったので合算
2026-11-13 0 ← 11-30 まで 0 が並ぶ
この SQL は Dashboard Pro のペインにもそのまま貼れます(実測: 30 行 / 372 ms)。棒グラフにすると、売れなかった日も軸に並ぶのでグラフが途切れません。
書くときに気をつけるところ:
-
GENERATE_SERIESはWITHの中(CTE の本体)に書きます。SELECT GENERATE_SERIES(…)とは書けません - 刻みは第 3 引数です(
'1 month'で月初が並び、数値ならGENERATE_SERIES(1, 10, 2)で 1, 3, 5, 7, 9) -
LEFT JOINで欠けた側は空文字なので、CASE WHEN d.合計 = '' THEN 0 …で 0 にします - 文字列はシングルクォートです(
"鳥取県"と書くとKSQL1201 予期しない文字になります)
導入のときも、分割すれば特別なことは要らない
10 年分をまとめて読む必要はありません。「この年を集計し直す」を年を変えて 10 回押すだけです。
1 回 9,400 件なので、kSQL アクション側の読み取りの上限も既定(10,000)のままで足ります。設定をいじらずに済むのは大きくて、「データが増えたら上限も上げる」という運用を抱え込まずに済みます。
実測
開発環境で測った数字です。
| 値 | |
|---|---|
| 読んだ件数 | 1 年 9,400 件 |
| 書いた件数 | 47 行 |
| かかった時間 | 6〜8 秒 |
| API | 23 回(読み 19 + 書き 1 + ログ 3) |
| 10 年分(ボタンを 10 回) | 470 行・230 回・1 分少々 |
10 回とも API は同じ 23 回で、ぶれたのは時間だけでした。
ダッシュボード側はこうです。
| ペイン | 表示 | 結果 |
|---|---|---|
| 10 年の売上合計 | KPI カード | 1 行 / 267 ms |
| 年別の売上 | 棒 | 10 行 / 326 ms |
| 都道府県の上位(10 年の合計) | 横棒 | 10 行 / 387 ms |
| 上位 5 県の年別 | 表 | 50 行 / 321 ms |
どれも 0.3 秒前後。470 行しか読まないので当然です。
ダッシュボードのペイン
Dashboard Pro のテンプレート(KPI カード・カテゴリ別・ランキングなど)は、分類フィールドに選択肢の項目しか選べません。都道府県を文字列1行にしていると候補に出ないので、空のペインに kSQL を直接書きました。
-- 年別の売上(棒)
SELECT 年, SUM(売上) AS 売上 FROM LAPP_集計 GROUP BY 年 ORDER BY 年;
-- 都道府県の上位(横棒)
SELECT 都道府県, SUM(売上) AS 売上 FROM LAPP_集計 GROUP BY 都道府県 ORDER BY 売上 DESC LIMIT 10;
どちらも kSQL なので、アクション側と同じ書き方で済みます。都道府県をドロップダウンにしておけば、テンプレートからも作れます。
線引き(できないこと)
正直に書いておきます。
- kSQL アクションは押した人のブラウザーで動きます。夜間バッチはできません。 誰かがボタンを押します。定期実行が要るなら kSQL Flow(CLI)や kSQL ジョブ実行プラグインの領分です
-
1 年だけ見るなら、事前集計は要りません。
WHEREに書いた kintone の関数は REST にそのまま渡るので、絞り込みだけで足ります。事前集計が効くのは、年をまたいで横に並べたいときです -
GROUP BYのあるUPSERTは、元が 0 件のグループを書きません。 放っておくと消えた都道府県の行が前の値のまま残り、合計がずれます。上の「消えた都道府県を 0 にする」の形にしてください
まとめ
- Dashboard Pro の上限はペインごとに 500〜50,000 件(既定 10,000)。10 年分 10 万件は上限を上げても届かない
- 件数より先に効くのは API。複数の人が何回も開くので、1 日 5,700 回が 400 回になる差は大きい(10 人 × 10 回。直接のほうは試算、集計のほうは実測)
- 上限に当てない設計にする。今回のデータなら年ごとに分けるだけで、読み取りの上限(既定 10,000)に収まる。1 年が 10,000 件を超えたら、上限を上げるのではなく分割の単位を細かくする(月単位にするなら、集計キーも「年月 × 都道府県」に変える)
- 複合キーは連結した文字列 + 重複禁止、集計の軸は元のアプリに持たせる
- 消えたグループは 0 で更新する。連続した軸(日・月・年)は
GENERATE_SERIES×LEFT JOIN、飛び飛びのキーは 0 の行をUNION ALL
関連記事
- rex0220 kSQL アクションプラグイン
- ① 詳細画面編(ボタンとイベント)
- ② 一覧編(選択したレコードをまとめて処理する)
- ③ 集計編(顧客別集計とテーブルへの書き戻し)
- ④ 運用編(ログアプリ・二重実行の防止・権限)
- ⑤ 事例編(10 万件を集計して Dashboard Pro で見る)(この記事)
- ⑥ イベント編(保存・ステータス変更・削除で自動実行する)
- ⑦ オーサリング編(設定を AI に作ってもらう)
- ⑧ 請求データ編(全体再計算で整合性を保つ)
- ⑨ 締めの画面編(押し忘れに気づくダッシュボード)
- ⑩ 画面のどこに出すか(ボタン・メニュー・パネルの使い分け)
- ⑪ 日本語・英語・中国語で使う(共通の文と多言語)
- ⑫ オーサリング改善編(AI に使わせて見つけた穴)
- 事例集(やりたいことから探す)





