Tips早見表
- 日本語住所の切り出し →
ifelse+locate+substring(郡・市・区を判定、locateは見つからないと0を返す) - 文字列型の日付 →
parseDate({フィールド}, 'yyyy/MM/dd')で日付型に変換してから日付関数を使う - 4月始まりの年度 →
extract('MM', ...)で月を取り出し、4月未満なら前年扱いにする - 重複排除 → まず
distinctCountを検討(rank + PRE_AGGはフィルタとの相性に注意) -
IN演算子は使えない →ORチェーンで代用 -
ifelse内のAND型エラー →ANDの前に両方のフィールドをparseDateなどで同じ型に揃える - 数字が合わないときは「元データ→データの繋ぎ合わせ→フィルター→計算フィールド」の順に疑う
はじめに
2026年4月、長年過ごした事務部門から情報システムの部署へ異動になりました。アルファベットの知らない専門用語に戸惑い、依頼や相談事の意味すら分からない、というところからのスタートでした。
その中で立ちはだかったのが、Excelからの置き換えで向き合うことになったQuickSightの計算フィールドです。最初は「何が分からないのかが分からない」状態でしたが、もともと関数おたくな性分なので、「これめちゃくちゃ便利じゃん」と気づいてからは単純に面白くなってきました。
この記事は、そんな悪戦苦闘の記録です。同じように非エンジニアでBIツールと向き合うことになった方の、ちょっとした参考になれば嬉しいです。
日本語住所から市区郡を抽出する
住所データが1つのフィールドにまとめて入っていて、そこから「市区郡」だけを取り出したい、という要件がありました。ExcelならLEFTやFINDでサクッと処理していたところですが、QuickSightではifelse・locate・substringを組み合わせて書きます。
ifelse(
locate({住所}, '郡') > 0,
substring({住所}, 1, locate({住所}, '郡') + 1),
ifelse(
locate({住所}, '市') > 0,
substring({住所}, 1, locate({住所}, '市')),
ifelse(
locate({住所}, '区') > 0,
substring({住所}, 1, locate({住所}, '区')),
{住所}
)
)
)
考え方はシンプルで、
- 「郡」という文字が住所の中にあるか
locateで位置を探す - あれば、その位置までを
substringで切り出す - なければ「市」で同じことをする
- それもなければ「区」で同じことをする(東京23区や政令指定都市の区に対応)
- どれもなければ住所全体をそのまま返す
という、いわば「文字列の中から目印を探して、そこまでを切り取る」処理です。
locateは見つからない場合0を返すので、> 0で「見つかったかどうか」を判定できるのがポイントです。ここを忘れてlocateの結果をそのまま条件に使うと、思った通りに分岐してくれません。
住所から「市区郡」を取り出したのは、地域ごとの対象件数を把握して、担当者や店舗の配属を判断しやすくするためです。この粒度は最初から決まっていたわけではなく、当初の担当店舗ごとの集計を確認してもらった後、「もっと細かい単位で見たい」という要望を受けて決まりました。
都道府県や市区郡をExcelの計算式で取り出す作業自体は、実はこれまでも何度もやってきたことです。QuickSightで求められたのも、結局は同じこと。でも、実際に組んでみて一番「これはいい!」と思ったのは、計算式の書き方そのものより別のところでした。Excelだと、対象リストが増えたり変わったりするたびに、抽出・整頓・提出という一連の作業が発生します。ひな型をどれだけ使い回しても、この作業自体は毎回外せませんでした。
QuickSightはデータベースと直接つながっているので、リアルタイムで状況が分かるし、一度計算フィールドを組んでしまえば、あとはもうずっとそのまま。データの抽出期間を間違える、貼り間違えるといった単純ミスも起こりません。担当が変わったときの引き継ぎもいらなくなります。
文字列型の日付を扱う
QuickSightで日付関連の関数(extractやdateDiffなど)を使おうとしたら、エラーになったり期待通りに動かなかったり。「なんで?」となった原因は、データセット側でその項目が「日付型」ではなく「文字列型」として読み込まれていたことでした。
見た目は2026/07/30のようにいかにも日付なのに、QuickSight内部では単なる文字列扱い。日付関数が素通りしてしまいます。ここでハマったときの解決策がparseDateです。
parseDate({工事日}, 'yyyy/MM/dd')
{工事日}が文字列型でyyyy/MM/dd形式(例:2026/07/30)のとき、このように書くことで日付型に変換してくれます。フォーマット文字列は元データの並びと正確に一致させる必要があり、たとえば2026-07-30のようにハイフン区切りなら'yyyy-MM-dd'に変える必要があります。
一度日付型に変換してしまえば、あとはextractやdateDiffなどの日付関数が普通に使えるようになります。逆に言うと、日付関連の関数がなぜか効かないときは、まずその項目が本当に日付型になっているか疑ってみる、というのが教訓です。
年度(4月始まり)の集計
日本の会社でありがちな「4月始まり」の年度集計。QuickSightには年度専用の関数はないので、extractで月と年を取り出して自分で組み立てる必要があります。
ifelse(
extract('MM', {工事日}) >= 4,
extract('YYYY', {工事日}),
extract('YYYY', {工事日}) - 1
)
考え方はこうです。
-
extract('MM', ...)で月を取り出す - 4月以降なら、その年がそのまま年度
- 1〜3月なら、前年が年度(例:2027年1月は「2026年度」)
例えば2027/01/15なら、月は1なので4月未満 → 年度は2027 - 1 = 2026年度、という計算になります。
なお、このextractが使えるのは対象のフィールドが日付型になっている場合に限られるので、前のセクションのparseDateとセットで使うことが多いです。文字列型のままだとextractもエラーになるので注意が必要です。
フィルタに連動した重複排除(distinctCount vs rank+PRE_AGG)
「同じ案件が複数行にわたって存在するデータから、ユニークな件数だけをカウントしたい」という場面がありました。最初に思いついたのはrank関数とPRE_AGGを使う方法でしたが、これがフィルタと組み合わせたときにうまく動いてくれず……。
具体的には、ダッシュボード側でフィルタ(期間や担当者で絞り込むなど)をかけると、rank + PRE_AGGで作った重複排除ロジックがフィルタ前の状態を基準に計算されてしまい、表示件数と実際の絞り込み結果が合わなくなる、という現象が起きました。
PRE_AGGは集計(グラフやテーブルへの表示)が行われる前、行レベルの段階で計算が確定してしまうため、その後にビジュアル側でフィルタをかけても、rankの計算自体はやり直されません。一方distinctCountは本来の集計関数なので、表示のたびにフィルタ後のデータに対して計算し直されます。この「いつ計算されるか」の違いが、両者の挙動の差につながっていました。
そこで行き着いたのがdistinctCountです。
distinctCount({管理番号})
案件を一意に識別できるキー(このケースでは「管理番号」)に対してdistinctCountを使うだけで、フィルタの状態に連動したユニーク件数があっさり取れるようになりました。
教訓
- 重複排除がしたいとき、まず
distinctCountで済むかどうかを検討する -
rank + PRE_AGGは集計のタイミング(フィルタ適用前か後か)を意識しないと、意図しない挙動になりやすい - シンプルに書ける方法があるなら、そちらを優先したほうが事故が少ない
地味にハマる仕様(IN演算子・ifelse内のAND型エラー)
最後に、地味だけど何度も引っかかった小ネタを2つ。
IN演算子が使えない
SQLに慣れていると、つい
{都道府県} IN ('東京都', '神奈川県', '千葉県')
のような書き方をしたくなるのですが、QuickSightの計算フィールドにはIN演算子がありません。代わりにORを並べて書く必要があります。
ifelse(
{都道府県} = '東京都' OR {都道府県} = '神奈川県' OR {都道府県} = '千葉県',
'関東',
'その他'
)
候補が少なければまだいいのですが、10個、20個と増えてくると一気に読みにくくなるのが悩みどころです。
ifelse内のANDで型エラーが起きる
ifelseの条件部分にANDを使うとき、比較する項目の型が揃っていないと型エラーになることがありました。
ifelse(
{工事日} IS NOT NULL AND {完工日} IS NOT NULL,
dateDiff({工事日}, {完工日}, 'DD'),
NULL
)
このような書き方自体は問題なさそうに見えても、片方が文字列型のまま(parseDateされていない)だったりすると、型が一致しない旨のエラーが出ることがあります。エラーメッセージだけを見ても原因が分かりにくいので、「型が揃っているか」をまず疑うのがコツです。
回避策としては、ANDの前に両方のフィールドを確実に日付型へ揃えておくのが一番シンプルでした。
ifelse(
parseDate({工事日}, 'yyyy/MM/dd') IS NOT NULL AND parseDate({完工日}, 'yyyy/MM/dd') IS NOT NULL,
dateDiff(parseDate({工事日}, 'yyyy/MM/dd'), parseDate({完工日}, 'yyyy/MM/dd'), 'DD'),
NULL
)
ANDで組み合わせる前に、両方の項目を同じ型に変換しておく。これだけで型エラーはかなり減りました。
「何かおかしい」と思ったときの切り分け方
計算フィールドを書いていると、「あれ、数字が合わない」という場面によく出くわします。そんなとき、原因になり得る場所はだいたい4つに絞られます。
-
元データ自体がおかしいのか
- そもそもソース側の値が間違っている、欠損している
-
データの繋ぎ合わせがおかしいのか
- 複数のデータセットを結合している場合、キーの粒度がズレていて重複や欠落が起きている
-
フィルターがおかしいのか
- ダッシュボード側のフィルタが、意図しない条件で絞り込んでしまっている
-
計算フィールドがおかしいのか
- ここまでの3つが正しければ、ようやく計算式そのものを疑う
厄介なのは、この4つのどこに原因があっても「表示されている数字が変」という同じ症状に見えることです。計算フィールドを疑って式をこねくり回す前に、まず元データとフィルタの状態を確認する、という順番を意識するようになりました。
体感としては、計算フィールドそのものが原因だったケースより、元データやフィルタの設定が原因だったケースの方が多かった気がします。
まとめ
データの取り扱いは、正直まったくの未経験からのスタートでした。QuickSightの計算フィールドも、最初は右も左も分かりません。
でもやってみて分かったのは、結局のところ「調べる」「試す」「きく」って、これまでやってきたことと同じだということ。部署が変わっても、仕事としてやることは同じなんだと気づきました。
- 住所抽出は、現場の方に「どの粒度で見たいか」を聞いて、初めて正解の式にたどり着きました
- 日付や年度計算は、エラーメッセージを読んで、ドキュメントを調べて、試して、を繰り返した結果です
- 「何かおかしい」と思ったときの切り分けも、原因を一つずつ調べて試していく作業そのものです
知ったかぶりをせず、素直に調べて、試して、聞く。地味だけど、これが一番の近道でした。Excel時代の抽出・整頓・提出という一連の手作業がなくなり、引き継ぎの手間もいらなくなったのが、地味だけど一番の成果だったと思います。
もう一つ、異動して「おもしろーい」と思ったのは、データを自分の手で触れるようになったことです。前の部署にいた頃は「データってどこにあるん?」状態で、誰かに頼んで、待って、出てきたものを見る、が当たり前でした。それが今では、自分で探して、自分で取り出せる。この変化は、正直ちょっと感動しました。
というわけで、次のミッションは「活用」です。せっかく現場に近い場所から異動してきたので、その視点を活かして、データを"作る人"から"使い倒す人"になっていきたいなと思っています。