[{"rendered_body":"\u003ch2 data-sourcepos=\"1:1-1:18\"\u003e\n\u003cspan id=\"0-はじめに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#0-%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e0. はじめに\u003c/h2\u003e\n\u003cul data-sourcepos=\"2:1-5:0\"\u003e\n\u003cli data-sourcepos=\"2:1-2:72\"\u003e2026年2月に\u003cstrong\u003ekintone認定アソシエイト試験\u003c/strong\u003eに合格した\u003c/li\u003e\n\u003cli data-sourcepos=\"3:1-3:200\"\u003eこの記事では、合格までに行った勉強方法に加えて、実際に勉強してみて重要だと感じた「ヘルプページの読み方」「問題文の読み方」をまとめる\u003c/li\u003e\n\u003cli data-sourcepos=\"4:1-5:0\"\u003eこれから受験する方の学習方針決めの参考になれば嬉しい\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"6:1-6:10\"\u003e\n\u003cspan id=\"目次\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%9B%AE%E6%AC%A1\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e目次\u003c/h3\u003e\n\u003cp data-sourcepos=\"8:1-11:115\"\u003e\u003ca href=\"#1-%E7%AD%86%E8%80%85%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e1. 筆者について\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"#2-%E3%81%AA%E3%81%9C%E5%8F%97%E9%A8%93%E3%81%97%E3%81%9F%E3%81%8B\"\u003e2. なぜ受験したか\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"#3-%E5%8B%89%E5%BC%B7%E6%9C%9F%E9%96%93%E7%B5%90%E6%9E%9C\"\u003e3. 勉強期間・結果\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"#4-%E5%90%88%E6%A0%BC%E3%81%97%E3%81%A6%E5%AE%9F%E5%8B%99%E3%81%A7%E5%BD%B9%E7%AB%8B%E3%81%A3%E3%81%9F%E3%81%A8%E6%80%9D%E3%81%86%E3%81%93%E3%81%A8\"\u003e4. 合格して実務で役立ったと思うこと\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"13:1-16:86\"\u003e\u003ca href=\"#5-%E5%8B%89%E5%BC%B7%E6%96%B9%E6%B3%95\"\u003e5. 勉強方法\u003c/a\u003e\u003cbr\u003e\n├\u003ca href=\"#5-1-%E3%83%8D%E3%83%83%E3%83%88%E4%B8%8A%E3%81%AE%E5%90%88%E6%A0%BC%E4%BD%93%E9%A8%93%E8%A8%98%E3%82%92%E8%AA%AD%E3%81%BF%E6%BC%81%E3%82%8B\"\u003e5-1. ネット上の合格体験記を読み漁る\u003c/a\u003e\u003cbr\u003e\n├\u003ca href=\"#5-2-%E8%A9%A6%E9%A8%93%E3%81%AE%E7%89%B9%E5%BE%B4%E3%82%92%E6%8A%BC%E3%81%95%E3%81%88%E3%82%8B\"\u003e5-2. 試験の特徴を押さえる\u003c/a\u003e\u003cbr\u003e\n└\u003ca href=\"#5-3-%E4%BD%BF%E7%94%A8%E6%95%99%E6%9D%90%E3%81%A8%E3%81%9D%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9\"\u003e5-3. 使用教材とその使い方\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"18:1-20:80\"\u003e\u003ca href=\"#6-%E5%AD%A6%E7%BF%92%E6%99%82%E3%81%AB%E6%84%8F%E8%AD%98%E3%81%97%E3%81%9F%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%84%E3%81%A8%E6%80%9D%E3%81%86%E3%81%93%E3%81%A8\"\u003e6. 学習時に意識した方が良いと思うこと\u003c/a\u003e\u003cbr\u003e\n├\u003ca href=\"#%E4%BE%8B%E3%81%BB%E3%81%8B%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E5%86%8D%E5%88%A9%E7%94%A8\"\u003e例①「ほかのアプリを再利用」\u003c/a\u003e\u003cbr\u003e\n└\u003ca href=\"#%E4%BE%8B%E8%A4%87%E6%95%B0%E8%A1%8C%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89\"\u003e例②「複数行フィールド」\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"22:1-24:149\"\u003e\u003ca href=\"#7-%E8%A9%A6%E9%A8%93%E6%99%82%E3%81%AB%E6%84%8F%E8%AD%98%E3%81%97%E3%81%9F%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%84%E3%81%A8%E6%80%9D%E3%81%86%E3%81%93%E3%81%A8\"\u003e7. 試験時に意識した方が良いと思うこと\u003c/a\u003e\u003cbr\u003e\n├\u003ca href=\"#%E3%81%82%E3%82%8C%E3%81%B0%E3%81%AF%E3%81%95%E3%81%88%E3%81%82%E3%82%8C%E3%81%B0%E3%81%A8%E8%AA%AD%E3%81%BF%E6%9B%BF%E3%81%88%E3%82%8B\"\u003e①「あれば」は「さえあれば」と読み替える\u003c/a\u003e\u003cbr\u003e\n└\u003ca href=\"##%E3%81%99%E3%81%B9%E3%81%A6%E9%81%B8%E3%81%B9%E7%B3%BB%E5%95%8F%E9%A1%8C%E3%81%AF2or3%E5%80%8B%E3%81%8C%E7%AD%94%E3%81%88%E3%81%AE%E7%A2%BA%E7%8E%87%E3%81%8C%E9%AB%98%E3%81%84\"\u003e②「すべて選べ」系問題は2or3個が答えの確率が高い\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"26:1-27:241\"\u003e\u003ca href=\"#8-%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e8. さいごに\u003c/a\u003e\u003cbr\u003e\n\u003ca href=\"#9-%E3%81%8A%E3%81%BE%E3%81%91%E3%81%9D%E3%81%AE%E4%BB%96%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%E3%81%86%E3%81%88%E3%81%A7%E6%B0%97%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E3%81%A8%E3%81%8B%E3%82%84%E3%82%84%E3%81%93%E3%81%97%E3%81%84%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E3%81%A8%E3%81%8B\"\u003e9. 【おまけ】その他問題を解くうえで気になったこととかややこしいと思ったこととか\u003c/a\u003e\u003c/p\u003e\n\u003ch2 data-sourcepos=\"31:1-31:24\"\u003e\n\u003cspan id=\"1-筆者について\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E7%AD%86%E8%80%85%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. 筆者について\u003c/h2\u003e\n\u003cul data-sourcepos=\"32:1-35:114\"\u003e\n\u003cli data-sourcepos=\"32:1-32:42\"\u003e新卒2年目（※資格受験当時）\u003c/li\u003e\n\u003cli data-sourcepos=\"33:1-33:50\"\u003e文系・プログラミング未経験で入社\u003c/li\u003e\n\u003cli data-sourcepos=\"34:1-34:84\"\u003e業務ではCSS / JavaScript (TypeScript) を用いたkintoneのカスタマイズ\u003c/li\u003e\n\u003cli data-sourcepos=\"35:1-35:114\"\u003ekintoneの機能についての勉強は、1年前にPJ参画時に視聴した動画教材のみ（↓これ）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ciframe width=\"100%\" height=\"315\" src=\"https://www.youtube.com/embed/videoseries?si=HKI1zp1OjO6yC_5K\u0026amp;list=PL7Mp3Q45NKA8rooYeagsOZUp6eWG0LdVb\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cul data-sourcepos=\"38:1-40:0\"\u003e\n\u003cli data-sourcepos=\"38:1-38:173\"\u003e資格勉強開始時点まで、主要な機能以外はほとんど忘れていた（業務では標準機能よりカスタマイズの知見が必要になるため）\u003c/li\u003e\n\u003cli data-sourcepos=\"39:1-40:0\"\u003e「アクション」機能を知らなかった\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"41:1-41:27\"\u003e\n\u003cspan id=\"2-なぜ受験したか\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E3%81%AA%E3%81%9C%E5%8F%97%E9%A8%93%E3%81%97%E3%81%9F%E3%81%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. なぜ受験したか\u003c/h2\u003e\n\u003cul data-sourcepos=\"42:1-43:0\"\u003e\n\u003cli data-sourcepos=\"42:1-43:0\"\u003ekintoneでお仕事をしているのに、主要機能以外の知識が少ないことに若干後ろめたさがあったから\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"44:1-44:27\"\u003e\n\u003cspan id=\"3-勉強期間結果\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E5%8B%89%E5%BC%B7%E6%9C%9F%E9%96%93%E7%B5%90%E6%9E%9C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. 勉強期間・結果\u003c/h2\u003e\n\u003cul data-sourcepos=\"45:1-53:0\"\u003e\n\u003cli data-sourcepos=\"45:1-45:68\"\u003e勉強期間：1ヶ月（おそらく合計40時間くらい？）\u003c/li\u003e\n\u003cli data-sourcepos=\"46:1-46:32\"\u003e受験結果：合格（80%）\u003c/li\u003e\n\u003cli data-sourcepos=\"47:1-53:0\"\u003e分野別成績\n\u003cul data-sourcepos=\"48:3-53:0\"\u003e\n\u003cli data-sourcepos=\"48:3-48:19\"\u003eアプリ：79%\u003c/li\u003e\n\u003cli data-sourcepos=\"49:3-49:23\"\u003eスペース：100%\u003c/li\u003e\n\u003cli data-sourcepos=\"50:3-50:25\"\u003e管理者設定：71%\u003c/li\u003e\n\u003cli data-sourcepos=\"51:3-51:19\"\u003eその他：83%\u003c/li\u003e\n\u003cli data-sourcepos=\"52:3-53:0\"\u003e応用：75%\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"54:1-54:54\"\u003e\n\u003cspan id=\"4-合格して実務で役立ったと思うこと\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-%E5%90%88%E6%A0%BC%E3%81%97%E3%81%A6%E5%AE%9F%E5%8B%99%E3%81%A7%E5%BD%B9%E7%AB%8B%E3%81%A3%E3%81%9F%E3%81%A8%E6%80%9D%E3%81%86%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4. 合格して実務で役立ったと思うこと\u003c/h2\u003e\n\u003cul data-sourcepos=\"55:1-57:0\"\u003e\n\u003cli data-sourcepos=\"55:1-55:110\"\u003eお客様からの質問にその場で答えられる瞬間がほんの少し（？）増えた（かも）\u003c/li\u003e\n\u003cli data-sourcepos=\"56:1-57:0\"\u003e資格取得そのものだけで実務力が急に伸びるわけではないが、標準機能の知識を体系的に確認する機会としては十分意味があった\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"58:1-58:18\"\u003e\n\u003cspan id=\"5-勉強方法\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#5-%E5%8B%89%E5%BC%B7%E6%96%B9%E6%B3%95\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e5. 勉強方法\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"59:1-59:54\"\u003e\n\u003cspan id=\"5-1-ネット上の合格体験記を読み漁る\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#5-1-%E3%83%8D%E3%83%83%E3%83%88%E4%B8%8A%E3%81%AE%E5%90%88%E6%A0%BC%E4%BD%93%E9%A8%93%E8%A8%98%E3%82%92%E8%AA%AD%E3%81%BF%E6%BC%81%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e5-1. ネット上の合格体験記を読み漁る\u003c/h3\u003e\n\u003cul data-sourcepos=\"60:1-65:0\"\u003e\n\u003cli data-sourcepos=\"60:1-65:0\"\u003e本当に皆さまお世話になりました。有益な情報をありがとうございました\u003cbr\u003e\n（他にも色々読みましたが特に参考にさせていただいたものを一部抜粋↓）。\n\u003cul data-sourcepos=\"62:3-65:0\"\u003e\n\u003cli data-sourcepos=\"62:3-62:188\"\u003e\u003ca href=\"https://zenn.dev/yankee/articles/consecutive_kintone_certification_exams\" rel=\"nofollow noopener\" target=\"_blank\"\u003ekintone認定試験（アソシエイト、アプリデザインスペシャリスト）受験記\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"63:3-63:164\"\u003e\u003ca href=\"https://oguemon.com/blog/2025-02-09/\" rel=\"nofollow noopener\" target=\"_blank\"\u003ekintone認定アソシエイト試験に合格したので勉強法を書きます | おぐえもんの日記\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"64:3-65:0\"\u003e\u003ca href=\"https://moritayugo.com/kintone-associate-textbook-necessity/\" rel=\"nofollow noopener\" target=\"_blank\"\u003ekintoneアソシエイトにテキストは不要？第4版を買わずに公式動画だけで合格した「14時間の時短歩き方」と重要メモ公開｜Yugo Morita Dev.\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"66:1-66:39\"\u003e\n\u003cspan id=\"5-2-試験の特徴を押さえる\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#5-2-%E8%A9%A6%E9%A8%93%E3%81%AE%E7%89%B9%E5%BE%B4%E3%82%92%E6%8A%BC%E3%81%95%E3%81%88%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e5-2. 試験の特徴を押さえる\u003c/h3\u003e\n\u003cul data-sourcepos=\"67:1-79:0\"\u003e\n\u003cli data-sourcepos=\"67:1-68:59\"\u003e\n\u003cp data-sourcepos=\"67:3-67:103\"\u003e\u003ca href=\"https://cybozu.co.jp/kintone-certification/aa_practice/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e公式の練習問題\u003c/a\u003e を解く\u003c/p\u003e\n\u003cul data-sourcepos=\"68:3-68:59\"\u003e\n\u003cli data-sourcepos=\"68:3-68:59\"\u003e初めての筆者の結果は18/45点（40%）\u003cbr\u003e\u003cbr\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"69:1-76:0\"\u003e\n\u003cp data-sourcepos=\"69:3-69:69\"\u003eこの試験の問題形式の\u003cstrong\u003eイヤな部分\u003c/strong\u003eが見えてきた\u003c/p\u003e\n\u003cul data-sourcepos=\"70:3-76:0\"\u003e\n\u003cli data-sourcepos=\"70:3-71:120\"\u003e\n\u003cstrong\u003e「正しい選択肢を選ぶ問題」と「誤っている選択肢を選ぶ問題」が混在している\u003c/strong\u003e\u003cbr\u003e\n（油断していると「誤っているもの」を選ぶべきなのに「正しいもの」を選んでしまう）\u003c/li\u003e\n\u003cli data-sourcepos=\"72:3-73:33\"\u003e\n\u003cstrong\u003e「すべて選べ」系問題の場合、正解になる選択肢が複数になる\u003c/strong\u003e\u003cbr\u003e\n（消去法が通用しない）\u003c/li\u003e\n\u003cli data-sourcepos=\"74:3-76:0\"\u003e\n\u003cstrong\u003e細かい制限値を問われる\u003c/strong\u003e\u003cbr\u003e\n（各フィールドにおける入力文字数上限とかCSVの上限サイズとか）\u003cbr\u003e\u003cbr\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"77:1-77:98\"\u003e\n\u003cp data-sourcepos=\"77:3-77:98\"\u003e本番でも同様の形式で多数出題されることを意識しながら勉強を進めた\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"78:1-79:0\"\u003e\n\u003cp data-sourcepos=\"78:3-78:188\"\u003eちなみに本番の試験では練習問題にはない「応用」セクションが用意されているが、他のセクションを勉強していれば問題なく突破できる\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"80:1-80:39\"\u003e\n\u003cspan id=\"5-3-使用教材とその使い方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#5-3-%E4%BD%BF%E7%94%A8%E6%95%99%E6%9D%90%E3%81%A8%E3%81%9D%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e5-3. 使用教材とその使い方\u003c/h3\u003e\n\u003cul data-sourcepos=\"82:1-93:0\"\u003e\n\u003cli data-sourcepos=\"82:1-84:115\"\u003e\n\u003ca href=\"https://jp.kintone.help/k/ja\" rel=\"nofollow noopener\" target=\"_blank\"\u003ekintoneヘルプ\u003c/a\u003eの以下のセクションをひたすら読む\n\u003cul data-sourcepos=\"83:3-84:115\"\u003e\n\u003cli data-sourcepos=\"83:3-83:105\"\u003e「アプリを作って運用する」内、\u003cstrong\u003e「アプリとは」～「Webhookの設定」まで\u003c/strong\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"84:3-84:115\"\u003e「kintoneの他の機能を使ってみる」内、\u003cstrong\u003e「データの検索」～「モバイル」まで\u003c/strong\u003e\u003cbr\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"85:1-87:136\"\u003e学習のメイン教材にkintoneヘルプを選択した理由：\n\u003cul data-sourcepos=\"86:3-87:136\"\u003e\n\u003cli data-sourcepos=\"86:3-86:140\"\u003eネット上の合格体験記を見ていると、「kintoneヘルプの内容がかなり出題される」旨の記載を多数確認\u003c/li\u003e\n\u003cli data-sourcepos=\"87:3-87:136\"\u003eWeb問題集を軽く解いてみるとテキストや動画のみでは太刀打ちできなさそうな雰囲気を感じたため\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"88:1-93:0\"\u003e勉強方法など\n\u003cul data-sourcepos=\"89:5-93:0\"\u003e\n\u003cli data-sourcepos=\"89:5-89:169\"\u003e辞書式の学習参考書のような細かすぎる説明と厚みがあるが、逆に言えば\u003cstrong\u003eこれさえ把握しておけば大抵の問題は解ける\u003c/strong\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"90:5-91:177\"\u003e\n\u003cstrong\u003eすでに知っている記述はガンガン飛ばしていき、知らなかったところや色付きの注意部分をスプレッドシートにまとめていた\u003c/strong\u003e\u003cbr\u003e\n※既におおよその機能を把握している場合に限り有効な方法であり、初学の場合は書籍や動画教材で概要を把握した方がよいと思う\u003c/li\u003e\n\u003cli data-sourcepos=\"92:5-93:0\"\u003e初知り機能や文面だけでのインプットが億劫な分野は適宜動画やテキストで捕捉した\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"94:1-94:57\"\u003e\n\u003cspan id=\"6-学習時に意識した方が良いと思うこと\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#6-%E5%AD%A6%E7%BF%92%E6%99%82%E3%81%AB%E6%84%8F%E8%AD%98%E3%81%97%E3%81%9F%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%84%E3%81%A8%E6%80%9D%E3%81%86%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e6. 学習時に意識した方が良いと思うこと\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"95:1-95:118\"\u003e\n\u003cspan id=\"結論aが記述されていたらaではない方āも確認しよう\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%B5%90%E8%AB%96a%E3%81%8C%E8%A8%98%E8%BF%B0%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%9F%E3%82%89a%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84%E6%96%B9%C4%81%E3%82%82%E7%A2%BA%E8%AA%8D%E3%81%97%E3%82%88%E3%81%86\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003cfont color=\"red\"\u003e\u003cstrong\u003e【結論】Aが記述されていたら、Aではない方（Ā）も確認しよう\u003c/strong\u003e\u003c/font\u003e\n\u003c/h3\u003e\n\u003ch4 data-sourcepos=\"96:1-96:47\"\u003e\n\u003cspan id=\"例ほかのアプリを再利用\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BE%8B%E3%81%BB%E3%81%8B%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E5%86%8D%E5%88%A9%E7%94%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e例①「ほかのアプリを再利用」\u003c/h4\u003e\n\u003cp data-sourcepos=\"97:1-97:63\"\u003e例えば、学習時に以下の記述を確認したとする\u003c/p\u003e\n\u003cblockquote data-sourcepos=\"98:1-112:14\"\u003e\n\u003cp data-sourcepos=\"98:3-98:119\"\u003eほかのアプリを再利用して作成したアプリには、次の項目の設定が引き継がれません。\u003c/p\u003e\n\u003cul data-sourcepos=\"100:2-112:14\"\u003e\n\u003cli data-sourcepos=\"100:2-100:22\"\u003eアプリコード\u003c/li\u003e\n\u003cli data-sourcepos=\"101:2-101:19\"\u003eAPIトークン\u003c/li\u003e\n\u003cli data-sourcepos=\"102:2-102:11\"\u003eWebhook\u003c/li\u003e\n\u003cli data-sourcepos=\"103:2-103:14\"\u003eSlack連携\u003c/li\u003e\n\u003cli data-sourcepos=\"104:2-105:65\"\u003e利用しているプラグインに適用している設定\u003cbr\u003e\nただし、有効／無効の状態は引き継がれます。\u003c/li\u003e\n\u003cli data-sourcepos=\"106:2-108:14\"\u003eアプリ管理者用メモ\u003cbr\u003e\nただし、アプリ管理者用メモの編集画面で［アプリテンプレートやアプリの再利用時にこのメモの内容を含める］にチェックが入っている場合は、引き継がれます。\u003cbr\u003e\n（中略）\u003c/li\u003e\n\u003cli data-sourcepos=\"109:2-112:14\"\u003eアプリのレコードのデータ\u003cbr\u003e\n再利用して作成したアプリのレコードは空の状態になります。\u003cbr\u003e\nアプリのレコードを引き継ぎたい場合は、再利用元のアプリからファイルにデータを書き出して、新しく作成したアプリに読み込みを行ってください。\u003cbr\u003e\n（後略）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003cp data-sourcepos=\"114:1-114:196\"\u003e引用以上：\u003ca href=\"https://jp.kintone.help/k/ja/app/setup/create_app/app_recycle\" rel=\"nofollow noopener\" target=\"_blank\"\u003eほかのアプリを再利用して新しく作成する（アプリのコピー） | kintone ヘルプ\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"116:1-120:0\"\u003e\n\u003cli data-sourcepos=\"116:1-117:0\"\u003e\n\u003cp data-sourcepos=\"116:3-116:209\"\u003eこれを最初に見た時、筆者は「要するに、フォーム内のフィールドに関する情報はそのまま引き継がれて、それ以外は引き継がれない」という理解をした\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"118:1-120:0\"\u003e\n\u003cp data-sourcepos=\"118:3-119:108\"\u003eしかし、この理解はかなり雑で、問題演習時に「アプリの再利用時、グラフの設定は引き継がれるか」と問われた際、「フィールドではない=引き継がれない」と判断して誤った回答をしてしまった\u003cbr\u003e\n※グラフの設定は引き継がれるらしい。ちなみに一覧の表示設定も引き継がれる\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"121:1-121:131\"\u003e\u003cfont color=\"red\"\u003e\u003cstrong\u003e★【教訓】列挙されている項目以外も、具体的に洗いだして線引きしよう★\u003c/strong\u003e\u003c/font\u003e\u003c/p\u003e\n\u003chr data-sourcepos=\"123:1-123:3\"\u003e\n\u003ch4 data-sourcepos=\"124:1-124:41\"\u003e\n\u003cspan id=\"例複数行フィールド\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BE%8B%E8%A4%87%E6%95%B0%E8%A1%8C%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e例②「複数行フィールド」\u003c/h4\u003e\n\u003cul data-sourcepos=\"125:3-130:0\"\u003e\n\u003cli data-sourcepos=\"125:3-125:273\"\u003e「複数行フィールド」のページ(\u003ca href=\"https://jp.kintone.help/k/ja/app/form/form_parts/text_box_multi-line\" rel=\"nofollow noopener\" target=\"_blank\"\u003e※\u003c/a\u003e)を見ても\u003cstrong\u003e文字数制限に関する記載がないので、「できる／できない」以前に全く意識していなかった\u003c/strong\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"126:3-127:97\"\u003e問題演習時に、「複数行フィールドは、文字数制限の設定ができる」という文を正誤判定する問題が出て困った\n\u003cul data-sourcepos=\"127:5-127:97\"\u003e\n\u003cli data-sourcepos=\"127:5-127:97\"\u003e\u003cstrong\u003e「できない」とも言ってないが、そもそも設定として存在しない\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"128:3-128:151\"\u003e逆に、「できない」として挙げられている項目があれば、「できる」方も意識した方がよい（例①のように）\u003c/li\u003e\n\u003cli data-sourcepos=\"129:3-130:0\"\u003e特にフォームの設定項目は、複数項目をまとめて比較して一度確認した方がよい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"131:1-131:123\"\u003e\u003cfont color=\"red\"\u003e\u003cstrong\u003e★【教訓②】★似たような項目同士は、細かい違いにも目を向けよう\u003c/strong\u003e \u003c/font\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"133:1-133:171\"\u003e例①でも例②でも、「じゃない方」もすべて細かく覚えるというよりは、一回洗いだして念のため確認するくらいで良いと思う\u003c/p\u003e\n\u003ch2 data-sourcepos=\"135:1-135:57\"\u003e\n\u003cspan id=\"7-試験時に意識した方が良いと思うこと\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#7-%E8%A9%A6%E9%A8%93%E6%99%82%E3%81%AB%E6%84%8F%E8%AD%98%E3%81%97%E3%81%9F%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%84%E3%81%A8%E6%80%9D%E3%81%86%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e7. 試験時に意識した方が良いと思うこと\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"136:1-136:64\"\u003e\n\u003cspan id=\"あればはさえあればと読み替える\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%82%E3%82%8C%E3%81%B0%E3%81%AF%E3%81%95%E3%81%88%E3%81%82%E3%82%8C%E3%81%B0%E3%81%A8%E8%AA%AD%E3%81%BF%E6%9B%BF%E3%81%88%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e①「あれば」は「さえあれば」と読み替える\u003c/h3\u003e\n\u003cp data-sourcepos=\"137:1-137:54\"\u003e例えば、以下の記述は正しいだろうか？\u003c/p\u003e\n\u003cul data-sourcepos=\"138:1-139:0\"\u003e\n\u003cli data-sourcepos=\"138:1-139:0\"\u003e\u003cstrong\u003e【アプリ作成時に「ほかのアプリを再利用」を利用するには、アプリの作成権限があればよい】\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"140:1-142:103\"\u003e→再利用元のアプリの管理権限も必要なため、これは誤りである\u003cbr\u003e\n「あれば」の意味をなんとなく曖昧に解釈してしまうと、このようなドツボにはまり、簡単な問題も落としてしまう\u003cbr\u003e\n\u003cstrong\u003e★「あれば」は「さえあれば」と脳内変換して、問題文を注意深く読もう\u003c/strong\u003e\u003c/p\u003e\n\u003chr data-sourcepos=\"144:1-144:3\"\u003e\n\u003ch3 data-sourcepos=\"145:1-145:74\"\u003e\n\u003cspan id=\"すべて選べ系問題は2or3個が答えの確率が高い\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%99%E3%81%B9%E3%81%A6%E9%81%B8%E3%81%B9%E7%B3%BB%E5%95%8F%E9%A1%8C%E3%81%AF2or3%E5%80%8B%E3%81%8C%E7%AD%94%E3%81%88%E3%81%AE%E7%A2%BA%E7%8E%87%E3%81%8C%E9%AB%98%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e②「すべて選べ」系問題は2or3個が答えの確率が高い\u003c/h3\u003e\n\u003cp data-sourcepos=\"146:1-147:139\"\u003eすべての問題は、4択の選択肢から正答を選ぶ形式である\u003cbr\u003e\n経験上、複数選択の問題で1個or4個が正解になることはないと思っている（過信はせずにお願いします）\u003c/p\u003e\n\u003ch2 data-sourcepos=\"149:1-149:18\"\u003e\n\u003cspan id=\"8-さいごに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#8-%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e8. さいごに\u003c/h2\u003e\n\u003cul data-sourcepos=\"150:1-152:0\"\u003e\n\u003cli data-sourcepos=\"150:1-150:252\"\u003e本試験に限らず、受験者の前提知識や実務経験は千差万別（せんさ\u003cstrong\u003eば\u003c/strong\u003eんべつ）になるので、この記事だけでなく色々な合格体験記を読み漁り、自分の学習方針を決定するとよいと思う\u003c/li\u003e\n\u003cli data-sourcepos=\"151:1-152:0\"\u003eおまけも見てね\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"153:1-153:120\"\u003e\n\u003cspan id=\"9-おまけその他問題を解くうえで気になったこととかややこしいと思ったこととか\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#9-%E3%81%8A%E3%81%BE%E3%81%91%E3%81%9D%E3%81%AE%E4%BB%96%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%E3%81%86%E3%81%88%E3%81%A7%E6%B0%97%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E3%81%A8%E3%81%8B%E3%82%84%E3%82%84%E3%81%93%E3%81%97%E3%81%84%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E3%81%A8%E3%81%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e9. 【おまけ】その他問題を解くうえで気になったこととかややこしいと思ったこととか\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e長いので折りたたみました\u003c/summary\u003e\n\u003cul data-sourcepos=\"158:1-172:0\"\u003e\n\u003cli data-sourcepos=\"158:1-159:79\"\u003e「kintoneに読込可能なExcelファイルのバージョン」として、ヘルプページや教材には「Excel 2007以降」って書いてるのに、問題ではバージョン名は記載されず拡張子で問うてくる\u003cbr\u003e\n（2007以降は.xlsx、それ以前は.xlsとなるため利用できない）\u003c/li\u003e\n\u003cli data-sourcepos=\"160:1-162:41\"\u003eレコード読込時にExcel or CSVを使う時の制限値は、Excel側の数値だけ覚えておけば列数以外は100倍することでCSVの制限値が分かる\n\u003cul data-sourcepos=\"161:3-162:41\"\u003e\n\u003cli data-sourcepos=\"161:3-161:40\"\u003eExcel：最大1MB、1000行、500列\u003c/li\u003e\n\u003cli data-sourcepos=\"162:3-162:41\"\u003eCSV：最大100MB、10万行、500列\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"163:1-163:134\"\u003e「日付」「時刻」「日時」フィールドのうち、唯一「時刻」フィールドだけは重複禁止にできない\u003c/li\u003e\n\u003cli data-sourcepos=\"164:1-164:163\"\u003e「時刻」フィールドが重複禁止にできないのは、0:00~23:59までの1440通りまでしか選べないからなのかなあ、と思っている\u003c/li\u003e\n\u003cli data-sourcepos=\"165:1-165:287\"\u003e「日付」「時刻」「日時」フィールドのうち、唯一「日時」フィールドだけがユーザーのタイムゾーンに沿って日時が表示される（日付フィールド、時刻フィールドはすべてのユーザーで同じ内容が表示される）\u003c/li\u003e\n\u003cli data-sourcepos=\"166:1-166:119\"\u003e「ラジオボタン」フィールドには選択必須かどうかを設定する項目がない（当たり前）\u003c/li\u003e\n\u003cli data-sourcepos=\"167:1-167:146\"\u003eファイル読込時に「ラジオボタン」フィールドの項目を空にしてると、初期値ではなく空のまま登録される\u003c/li\u003e\n\u003cli data-sourcepos=\"168:1-168:115\"\u003e「日付」「日時」フィールドで登録できる一番古い年の値は0年じゃなくて1000年から\u003c/li\u003e\n\u003cli data-sourcepos=\"169:1-169:134\"\u003e「グループ」フィールドと、「グループ選択」フィールドは別物。ぼーっとしてると見間違えそう\u003c/li\u003e\n\u003cli data-sourcepos=\"170:1-172:0\"\u003eショートカット覚えるの難しい。アルファベット割り当ての根拠になる英単語があるはずなんだから公開してくれたらいいのに。チャッピーたすけて～\u003cbr\u003e\n🤖＜承知しました\u003c/li\u003e\n\u003c/ul\u003e\n\u003ctable data-sourcepos=\"173:1-180:280\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"173:1-173:22\"\u003e\n\u003cth data-sourcepos=\"173:2-173:12\"\u003e見出し\u003c/th\u003e\n\u003cth data-sourcepos=\"173:14-173:21\"\u003e内容\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"175:1-175:480\"\u003e\n\u003ctd data-sourcepos=\"175:2-175:77\"\u003e■ 共通で使えるショートカットキー（複数画面で共通）\u003c/td\u003e\n\u003ctd data-sourcepos=\"175:79-175:479\"\u003e/ : 検索キーワードを入力する\u003cbr\u003e? : ［ショートカットキーの一覧］画面の表示／非表示\u003cbr\u003ej : 次のレコード／通知を選択する\u003cbr\u003ek : 前のレコード／通知を選択する\u003cbr\u003ec : レコードを追加する（create）\u003cbr\u003ee : レコードを編集する（edit）\u003cbr\u003eCtrl + s : 変更を保存する\u003cbr\u003e※ Ctrl + s は編集・追加系画面のみ有効\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"176:1-176:201\"\u003e\n\u003ctd data-sourcepos=\"176:2-176:35\"\u003e■ レコード一覧画面のみ\u003c/td\u003e\n\u003ctd data-sourcepos=\"176:37-176:200\"\u003eEnter / o : 選択したレコードの詳細を表示する\u003cbr\u003en : 次のページを表示する（next）\u003cbr\u003ep : 前のページを表示する（previous）\u003cbr\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"177:1-177:197\"\u003e\n\u003ctd data-sourcepos=\"177:2-177:44\"\u003e■ レコード詳細／編集画面のみ\u003c/td\u003e\n\u003ctd data-sourcepos=\"177:46-177:196\"\u003eesc : 編集をキャンセルする\u003cbr\u003eg a : レコード一覧に戻る（go + all）\u003cbr\u003eg i : 絞り込み結果に戻る（go + index/filter）\u003cbr\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"178:1-178:129\"\u003e\n\u003ctd data-sourcepos=\"178:2-178:71\"\u003e■ レコード追加／再利用画面のみ（専用キーなし）\u003c/td\u003e\n\u003ctd data-sourcepos=\"178:73-178:128\"\u003e※ 共通キー（/、?、Ctrl + s）のみ使用可能\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"179:1-179:722\"\u003e\n\u003ctd data-sourcepos=\"179:2-179:29\"\u003e■ 通知一覧画面のみ\u003c/td\u003e\n\u003ctd data-sourcepos=\"179:31-179:721\"\u003eEnter : 選択中の通知を開く\u003cbr\u003ee : 通知のボタン表示／非表示を切り替える\u003cbr\u003eg a : 絞り込みを［すべて］に切り替える（go + all）\u003cbr\u003eg m : 絞り込みを［自分宛］に切り替える（go + me）\u003cbr\u003eg r : 既読の通知を表示する（go + read）\u003cbr\u003eg s : 絞り込みを［あとで読む］に切り替える（go + saved）\u003cbr\u003eg u : 未読の通知を表示する（go + unread）\u003cbr\u003es : ［あとで読む］フラグを付け外しする（switch?）\u003cbr\u003ex : 未読／既読を切り替える\u003cbr\u003e【注意】\u003cbr\u003eアップデートオプションで新しい通知画面を有効化している場合、以下は無効。\u003cbr\u003e・e\u003cbr\u003e・g r\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"180:1-180:280\"\u003e\n\u003ctd data-sourcepos=\"180:2-180:29\"\u003e■ 通知詳細画面のみ\u003c/td\u003e\n\u003ctd data-sourcepos=\"180:31-180:279\"\u003es : ［あとで読む］フラグを付け外しする（saved）\u003cbr\u003eu : 通知一覧を表示する（unread）\u003cbr\u003e【注意】\u003cbr\u003eアップデートオプションで新しい通知画面を有効化している場合、以下は無効。\u003cbr\u003e・u\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp data-sourcepos=\"182:1-182:182\"\u003e※プロンプトに\u003ca href=\"https://jp.kintone.help/k/ja/common_operations/shortcuts\" rel=\"nofollow noopener\" target=\"_blank\"\u003ekintoneのショートカットキー | kintone ヘルプ\u003c/a\u003eの内容を貼り付けました\u003c/p\u003e\n\u003cp data-sourcepos=\"186:1-186:78\"\u003eおまけは以上。読んでいただきありがとうございました。\u003c/p\u003e\n\u003c/details\u003e","body":"## 0. はじめに\n- 2026年2月に**kintone認定アソシエイト試験**に合格した\n- この記事では、合格までに行った勉強方法に加えて、実際に勉強してみて重要だと感じた「ヘルプページの読み方」「問題文の読み方」をまとめる\n- これから受験する方の学習方針決めの参考になれば嬉しい\n\n### 目次\n\n\u003ca href=#1-筆者について\u003e1. 筆者について\u003c/a\u003e\n\u003ca href=#2-なぜ受験したか\u003e2. なぜ受験したか\u003c/a\u003e\n\u003ca href=#3-勉強期間結果\u003e3. 勉強期間・結果\u003c/a\u003e\n\u003ca href=#4-合格して実務で役立ったと思うこと\u003e4. 合格して実務で役立ったと思うこと\u003c/a\u003e\n\n\u003ca href=#5-勉強方法\u003e5. 勉強方法\u003c/a\u003e\n├\u003ca href=#5-1-ネット上の合格体験記を読み漁る\u003e5-1. ネット上の合格体験記を読み漁る\u003c/a\u003e\n├\u003ca href=#5-2-試験の特徴を押さえる\u003e5-2. 試験の特徴を押さえる\u003c/a\u003e\n└\u003ca href=#5-3-使用教材とその使い方\u003e5-3. 使用教材とその使い方\u003c/a\u003e\n\n\u003ca href=#6-学習時に意識した方が良いと思うこと\u003e6. 学習時に意識した方が良いと思うこと\u003c/a\u003e\n├\u003ca href=#例ほかのアプリを再利用\u003e例①「ほかのアプリを再利用」\u003c/a\u003e\n└\u003ca href=#例複数行フィールド\u003e例②「複数行フィールド」\u003c/a\u003e\n\n\u003ca href=#7-試験時に意識した方が良いと思うこと\u003e7. 試験時に意識した方が良いと思うこと\u003c/a\u003e\n├\u003ca href=#あればはさえあればと読み替える\u003e①「あれば」は「さえあれば」と読み替える\u003c/a\u003e\n└\u003ca href=##すべて選べ系問題は2or3個が答えの確率が高い\u003e②「すべて選べ」系問題は2or3個が答えの確率が高い\u003c/a\u003e\n\n\u003ca href=#8-さいごに\u003e8. さいごに\u003c/a\u003e\n\u003ca href=#9-おまけその他問題を解くうえで気になったこととかややこしいと思ったこととか\u003e9. 【おまけ】その他問題を解くうえで気になったこととかややこしいと思ったこととか\u003c/a\u003e\n\n\n\n## 1. 筆者について\n- 新卒2年目（※資格受験当時）\n- 文系・プログラミング未経験で入社\n- 業務ではCSS / JavaScript (TypeScript) を用いたkintoneのカスタマイズ\n- kintoneの機能についての勉強は、1年前にPJ参画時に視聴した動画教材のみ（↓これ）\n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/videoseries?si=HKI1zp1OjO6yC_5K\u0026amp;list=PL7Mp3Q45NKA8rooYeagsOZUp6eWG0LdVb\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen\u003e\u003c/iframe\u003e\n\n- 資格勉強開始時点まで、主要な機能以外はほとんど忘れていた（業務では標準機能よりカスタマイズの知見が必要になるため）\n- 「アクション」機能を知らなかった\n\n## 2. なぜ受験したか\n- kintoneでお仕事をしているのに、主要機能以外の知識が少ないことに若干後ろめたさがあったから\n\n## 3. 勉強期間・結果\n- 勉強期間：1ヶ月（おそらく合計40時間くらい？）\n- 受験結果：合格（80%）\n- 分野別成績\n  - アプリ：79%\n  - スペース：100%\n  - 管理者設定：71%\n  - その他：83%\n  - 応用：75%\n\n## 4. 合格して実務で役立ったと思うこと\n- お客様からの質問にその場で答えられる瞬間がほんの少し（？）増えた（かも）\n- 資格取得そのものだけで実務力が急に伸びるわけではないが、標準機能の知識を体系的に確認する機会としては十分意味があった\n\n## 5. 勉強方法\n### 5-1. ネット上の合格体験記を読み漁る\n- 本当に皆さまお世話になりました。有益な情報をありがとうございました\n（他にも色々読みましたが特に参考にさせていただいたものを一部抜粋↓）。\n  - \u003ca href=\"https://zenn.dev/yankee/articles/consecutive_kintone_certification_exams\"\u003ekintone認定試験（アソシエイト、アプリデザインスペシャリスト）受験記\u003c/a\u003e\n  - \u003ca href=\"https://oguemon.com/blog/2025-02-09/\"\u003ekintone認定アソシエイト試験に合格したので勉強法を書きます | おぐえもんの日記\u003c/a\u003e\n  - \u003ca href=\"https://moritayugo.com/kintone-associate-textbook-necessity/\"\u003ekintoneアソシエイトにテキストは不要？第4版を買わずに公式動画だけで合格した「14時間の時短歩き方」と重要メモ公開｜Yugo Morita Dev.\u003c/a\u003e\n\n### 5-2. 試験の特徴を押さえる\n- \u003ca href=\"https://cybozu.co.jp/kintone-certification/aa_practice/\"\u003e公式の練習問題\u003c/a\u003e を解く\n  - 初めての筆者の結果は18/45点（40%）\u003cbr\u003e\u003cbr\u003e\n- この試験の問題形式の**イヤな部分**が見えてきた\n  - **「正しい選択肢を選ぶ問題」と「誤っている選択肢を選ぶ問題」が混在している**\n（油断していると「誤っているもの」を選ぶべきなのに「正しいもの」を選んでしまう）\n  - **「すべて選べ」系問題の場合、正解になる選択肢が複数になる**\n（消去法が通用しない）\n  - **細かい制限値を問われる**\n（各フィールドにおける入力文字数上限とかCSVの上限サイズとか）\u003cbr\u003e\u003cbr\u003e\n\n- 本番でも同様の形式で多数出題されることを意識しながら勉強を進めた\n- ちなみに本番の試験では練習問題にはない「応用」セクションが用意されているが、他のセクションを勉強していれば問題なく突破できる\n\n### 5-3. 使用教材とその使い方\n\n- \u003ca href=\"https://jp.kintone.help/k/ja\"\u003ekintoneヘルプ\u003c/a\u003eの以下のセクションをひたすら読む\n  - 「アプリを作って運用する」内、**「アプリとは」～「Webhookの設定」まで**\n  - 「kintoneの他の機能を使ってみる」内、**「データの検索」～「モバイル」まで**\u003cbr\u003e\n- 学習のメイン教材にkintoneヘルプを選択した理由：\n  - ネット上の合格体験記を見ていると、「kintoneヘルプの内容がかなり出題される」旨の記載を多数確認\n  - Web問題集を軽く解いてみるとテキストや動画のみでは太刀打ちできなさそうな雰囲気を感じたため\n- 勉強方法など\n    - 辞書式の学習参考書のような細かすぎる説明と厚みがあるが、逆に言えば**これさえ把握しておけば大抵の問題は解ける**\n    - **すでに知っている記述はガンガン飛ばしていき、知らなかったところや色付きの注意部分をスプレッドシートにまとめていた**\n※既におおよその機能を把握している場合に限り有効な方法であり、初学の場合は書籍や動画教材で概要を把握した方がよいと思う\n    - 初知り機能や文面だけでのインプットが億劫な分野は適宜動画やテキストで捕捉した\n\n## 6. 学習時に意識した方が良いと思うこと\n### \u003cfont color=\"red\"\u003e**【結論】Aが記述されていたら、Aではない方（Ā）も確認しよう**\u003c/font\u003e\n#### 例①「ほかのアプリを再利用」\n例えば、学習時に以下の記述を確認したとする\n\u003e ほかのアプリを再利用して作成したアプリには、次の項目の設定が引き継がれません。\n\u003e \n\u003e-  アプリコード\n\u003e-  APIトークン\n\u003e-  Webhook\n\u003e- Slack連携\n\u003e-  利用しているプラグインに適用している設定\n\u003e ただし、有効／無効の状態は引き継がれます。\n\u003e-  アプリ管理者用メモ\n\u003e ただし、アプリ管理者用メモの編集画面で［アプリテンプレートやアプリの再利用時にこのメモの内容を含める］にチェックが入っている場合は、引き継がれます。\n\u003e （中略）\n\u003e-  アプリのレコードのデータ\n\u003e 再利用して作成したアプリのレコードは空の状態になります。\n\u003e アプリのレコードを引き継ぎたい場合は、再利用元のアプリからファイルにデータを書き出して、新しく作成したアプリに読み込みを行ってください。\n\u003e （後略）\n\n引用以上：\u003ca href =\"https://jp.kintone.help/k/ja/app/setup/create_app/app_recycle\"\u003eほかのアプリを再利用して新しく作成する（アプリのコピー） | kintone ヘルプ\u003c/a\u003e\n\n- これを最初に見た時、筆者は「要するに、フォーム内のフィールドに関する情報はそのまま引き継がれて、それ以外は引き継がれない」という理解をした\n\n- しかし、この理解はかなり雑で、問題演習時に「アプリの再利用時、グラフの設定は引き継がれるか」と問われた際、「フィールドではない=引き継がれない」と判断して誤った回答をしてしまった\n※グラフの設定は引き継がれるらしい。ちなみに一覧の表示設定も引き継がれる\n\n\u003cfont color=\"red\"\u003e**★【教訓】列挙されている項目以外も、具体的に洗いだして線引きしよう★**\u003c/font\u003e\n\n---\n#### 例②「複数行フィールド」\n  - 「複数行フィールド」のページ(\u003ca href=\"https://jp.kintone.help/k/ja/app/form/form_parts/text_box_multi-line\"\u003e※\u003c/a\u003e)を見ても**文字数制限に関する記載がないので、「できる／できない」以前に全く意識していなかった**\n  - 問題演習時に、「複数行フィールドは、文字数制限の設定ができる」という文を正誤判定する問題が出て困った\n    - **「できない」とも言ってないが、そもそも設定として存在しない**\n  - 逆に、「できない」として挙げられている項目があれば、「できる」方も意識した方がよい（例①のように）\n  - 特にフォームの設定項目は、複数項目をまとめて比較して一度確認した方がよい\n\n\u003cfont color=\"red\"\u003e**★【教訓②】★似たような項目同士は、細かい違いにも目を向けよう** \u003c/font\u003e\n\n例①でも例②でも、「じゃない方」もすべて細かく覚えるというよりは、一回洗いだして念のため確認するくらいで良いと思う\n\n## 7. 試験時に意識した方が良いと思うこと\n### ①「あれば」は「さえあれば」と読み替える\n例えば、以下の記述は正しいだろうか？\n- **【アプリ作成時に「ほかのアプリを再利用」を利用するには、アプリの作成権限があればよい】**\n\n→再利用元のアプリの管理権限も必要なため、これは誤りである\n「あれば」の意味をなんとなく曖昧に解釈してしまうと、このようなドツボにはまり、簡単な問題も落としてしまう\n**★「あれば」は「さえあれば」と脳内変換して、問題文を注意深く読もう**\n\n---\n### ②「すべて選べ」系問題は2or3個が答えの確率が高い\nすべての問題は、4択の選択肢から正答を選ぶ形式である\n経験上、複数選択の問題で1個or4個が正解になることはないと思っている（過信はせずにお願いします）\n\n## 8. さいごに\n- 本試験に限らず、受験者の前提知識や実務経験は千差万別（せんさ**ば**んべつ）になるので、この記事だけでなく色々な合格体験記を読み漁り、自分の学習方針を決定するとよいと思う\n- おまけも見てね\n\n## 9. 【おまけ】その他問題を解くうえで気になったこととかややこしいと思ったこととか\n\n\u003cdetails\u003e\n\u003csummary\u003e長いので折りたたみました\u003c/summary\u003e\n\n- 「kintoneに読込可能なExcelファイルのバージョン」として、ヘルプページや教材には「Excel 2007以降」って書いてるのに、問題ではバージョン名は記載されず拡張子で問うてくる\n（2007以降は.xlsx、それ以前は.xlsとなるため利用できない）\n- レコード読込時にExcel or CSVを使う時の制限値は、Excel側の数値だけ覚えておけば列数以外は100倍することでCSVの制限値が分かる\n  - Excel：最大1MB、1000行、500列\n  - CSV：最大100MB、10万行、500列\n- 「日付」「時刻」「日時」フィールドのうち、唯一「時刻」フィールドだけは重複禁止にできない\n- 「時刻」フィールドが重複禁止にできないのは、0:00~23:59までの1440通りまでしか選べないからなのかなあ、と思っている\n- 「日付」「時刻」「日時」フィールドのうち、唯一「日時」フィールドだけがユーザーのタイムゾーンに沿って日時が表示される（日付フィールド、時刻フィールドはすべてのユーザーで同じ内容が表示される）\n- 「ラジオボタン」フィールドには選択必須かどうかを設定する項目がない（当たり前）\n- ファイル読込時に「ラジオボタン」フィールドの項目を空にしてると、初期値ではなく空のまま登録される\n- 「日付」「日時」フィールドで登録できる一番古い年の値は0年じゃなくて1000年から\n- 「グループ」フィールドと、「グループ選択」フィールドは別物。ぼーっとしてると見間違えそう\n- ショートカット覚えるの難しい。アルファベット割り当ての根拠になる英単語があるはずなんだから公開してくれたらいいのに。チャッピーたすけて～\n🤖＜承知しました\n\n| 見出し | 内容 |\n|---|---|\n|■ 共通で使えるショートカットキー（複数画面で共通）|/ : 検索キーワードを入力する\u003cbr\u003e? : ［ショートカットキーの一覧］画面の表示／非表示\u003cbr\u003ej : 次のレコード／通知を選択する\u003cbr\u003ek : 前のレコード／通知を選択する\u003cbr\u003ec : レコードを追加する（create）\u003cbr\u003ee : レコードを編集する（edit）\u003cbr\u003eCtrl + s : 変更を保存する\u003cbr\u003e※ Ctrl + s は編集・追加系画面のみ有効|\n|■ レコード一覧画面のみ|Enter / o : 選択したレコードの詳細を表示する\u003cbr\u003en : 次のページを表示する（next）\u003cbr\u003ep : 前のページを表示する（previous）\u003cbr\u003e|\n|■ レコード詳細／編集画面のみ|esc : 編集をキャンセルする\u003cbr\u003eg a : レコード一覧に戻る（go + all）\u003cbr\u003eg i : 絞り込み結果に戻る（go + index/filter）\u003cbr\u003e|\n|■ レコード追加／再利用画面のみ（専用キーなし）|※ 共通キー（/、?、Ctrl + s）のみ使用可能|\n|■ 通知一覧画面のみ|Enter : 選択中の通知を開く\u003cbr\u003ee : 通知のボタン表示／非表示を切り替える\u003cbr\u003eg a : 絞り込みを［すべて］に切り替える（go + all）\u003cbr\u003eg m : 絞り込みを［自分宛］に切り替える（go + me）\u003cbr\u003eg r : 既読の通知を表示する（go + read）\u003cbr\u003eg s : 絞り込みを［あとで読む］に切り替える（go + saved）\u003cbr\u003eg u : 未読の通知を表示する（go + unread）\u003cbr\u003es : ［あとで読む］フラグを付け外しする（switch?）\u003cbr\u003ex : 未読／既読を切り替える\u003cbr\u003e【注意】\u003cbr\u003eアップデートオプションで新しい通知画面を有効化している場合、以下は無効。\u003cbr\u003e・e\u003cbr\u003e・g r|\n|■ 通知詳細画面のみ|s : ［あとで読む］フラグを付け外しする（saved）\u003cbr\u003eu : 通知一覧を表示する（unread）\u003cbr\u003e【注意】\u003cbr\u003eアップデートオプションで新しい通知画面を有効化している場合、以下は無効。\u003cbr\u003e・u|\n\n※プロンプトに\u003ca href=\"https://jp.kintone.help/k/ja/common_operations/shortcuts\"\u003ekintoneのショートカットキー | kintone ヘルプ\u003c/a\u003eの内容を貼り付けました\n\n\n\nおまけは以上。読んでいただきありがとうございました。\n\n","coediting":false,"comments_count":0,"created_at":"2026-04-29T20:43:59+09:00","group":null,"id":"87c52d617d8924f6c805","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"資格","versions":[]},{"name":"kintone","versions":[]},{"name":"資格勉強","versions":[]},{"name":"合格体験記","versions":[]},{"name":"kintone認定アソシエイト","versions":[]}],"title":"【細かすぎるぜ】kintone認定アソシエイトに合格したので、勉強時に引っかかったところを書く【合格体験記】","updated_at":"2026-04-29T20:43:59+09:00","url":"https://qiita.com/YYYYaMMaDDa/items/87c52d617d8924f6c805","user":{"description":null,"facebook_id":null,"followees_count":2,"followers_count":2,"github_login_name":null,"id":"YYYYaMMaDDa","items_count":5,"linkedin_id":null,"location":null,"name":"","organization":null,"permanent_id":4186356,"profile_image_url":"https://secure.gravatar.com/avatar/bfd226216a7ccdd4680ab5133c7b3a53","team_only":false,"twitter_screen_name":null,"website_url":null},"page_views_count":null,"team_membership":null,"organization_url_name":"ari-group","slide":false},{"rendered_body":"\u003ch2 data-sourcepos=\"2:1-2:15\"\u003e\n\u003cspan id=\"はじめに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eはじめに\u003c/h2\u003e\n\u003cp data-sourcepos=\"4:1-4:142\"\u003ekintoneのカスタマイズで「この処理、実行前にユーザーへ確認を取りたい」と感じたことはありませんか？\u003c/p\u003e\n\u003cp data-sourcepos=\"6:1-7:129\"\u003e実際、kintoneアプリでは「画面上の操作だけでは把握しきれない処理」や\u003cbr\u003e\n「一括登録・一括削除・ステータス変更など、取り消せない処理」を実装することがあります。\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-10:165\"\u003eこうした処理では、実行前にユーザーへ確認を取ることがUX設計として重要です。\u003cbr\u003e\n確認ダイアログを表示することで、処理の内容をユーザーの同意を得たうえで実行でき、誤操作のリスクを抑えられます。\u003c/p\u003e\n\u003cp data-sourcepos=\"12:1-15:90\"\u003e2025年9月〜2026年3月にかけて、kintone JavaScript APIでは\u003cbr\u003e\n\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-dialog/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003ecreateDialog()\u003c/code\u003e\u003c/a\u003e、\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-dialog/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003eshowConfirmDialog()\u003c/code\u003e\u003c/a\u003e、\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-notification/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003eshowNotification()\u003c/code\u003e\u003c/a\u003e、\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-loading/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003eshowLoading()\u003c/code\u003e\u003c/a\u003e、\u003cbr\u003e\n\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-bottomsheet/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003ecreateBottomSheet()\u003c/code\u003e\u003c/a\u003e、\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-bottomsheet/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003eshowConfirmBottomSheet()\u003c/code\u003e\u003c/a\u003e\u003cbr\u003e\nといったダイアログ・通知バナー系のAPIが新たに追加されました。\u003c/p\u003e\n\u003cp data-sourcepos=\"17:1-18:99\"\u003e本記事ではこれらのAPIを使って、ユーザーに確認・進捗・結果を伝えながら、\u003cbr\u003e\n処理を進める「ユーザー対話型カスタマイズ」の実装方法を解説します。\u003c/p\u003e\n\u003cp data-sourcepos=\"20:1-20:111\"\u003eまずは、最もシンプルに確認ダイアログを導入できる方法から見ていきましょう。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"22:1-22:63\"\u003e\n\u003cspan id=\"showconfirmdialog--確認ダイアログを表示する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#showconfirmdialog--%E7%A2%BA%E8%AA%8D%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003eshowConfirmDialog()\u003c/code\u003e : 確認ダイアログを表示する\u003c/h2\u003e\n\u003cp data-sourcepos=\"24:1-24:101\"\u003e「OK/キャンセル」で確認するだけなら、 \u003ccode\u003eshowConfirmDialog()\u003c/code\u003e が適しています。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"26:1-26:22\"\u003e\n\u003cspan id=\"使用場面の例\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BD%BF%E7%94%A8%E5%A0%B4%E9%9D%A2%E3%81%AE%E4%BE%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e使用場面の例\u003c/h3\u003e\n\u003cul data-sourcepos=\"28:1-31:0\"\u003e\n\u003cli data-sourcepos=\"28:1-28:50\"\u003eステータス変更前に確認がしたい。\u003c/li\u003e\n\u003cli data-sourcepos=\"29:1-29:68\"\u003e重要なアクションを実行する前に確認がしたい。\u003c/li\u003e\n\u003cli data-sourcepos=\"30:1-31:0\"\u003eシンプルにテキストのみの確認がしたい。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"32:1-32:49\"\u003e\n\u003cspan id=\"実装例ステータス変更前の確認\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E4%BE%8B%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E5%A4%89%E6%9B%B4%E5%89%8D%E3%81%AE%E7%A2%BA%E8%AA%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装例：ステータス変更前の確認\u003c/h3\u003e\n\u003cp data-sourcepos=\"34:1-34:191\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F81ac93e7-39f6-4c26-a913-a4e850f84916.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=d97616ab460a970e012ee07a948a3b47\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F81ac93e7-39f6-4c26-a913-a4e850f84916.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=d97616ab460a970e012ee07a948a3b47\" alt=\"showConfirmDialogによるステータス変更確認ダイアログの表示例\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F81ac93e7-39f6-4c26-a913-a4e850f84916.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=93d66ee6be3babdde8075a1b8e80279a 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/81ac93e7-39f6-4c26-a913-a4e850f84916.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"36:1-36:117\"\u003e次のコードは、プロセス管理のステータス変更前に確認ダイアログを表示する例です。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"38:1-59:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003euse strict\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n  \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eevents\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.detail.process.proceed\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003easync \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowConfirmDialog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n      \u003cspan class=\"na\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eステータス変更の確認\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eステータスを変更します。よろしいですか？\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowOkButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eokButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e変更する\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowCancelButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003ecancelButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eキャンセル\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowCloseButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\n    \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e!==\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eOK\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eerror\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eステータス変更がキャンセルされました。\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"61:1-61:22\"\u003e\n\u003cspan id=\"モバイル対応\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E5%AF%BE%E5%BF%9C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eモバイル対応\u003c/h3\u003e\n\u003cp data-sourcepos=\"63:1-64:193\"\u003eモバイル版では \u003ccode\u003ekintone.mobile.showConfirmBottomSheet()\u003c/code\u003e を使います。\u003cbr\u003e\n引数・戻り値の仕様は \u003ccode\u003eshowConfirmDialog()\u003c/code\u003e と同様で、モバイルデバイスの画面の下端に配置されるボトムシートと呼ばれるUIが提供されています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"66:1-66:73\"\u003e\n\u003cspan id=\"createdialog--入力フォーム付きのダイアログを作る\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#createdialog--%E5%85%A5%E5%8A%9B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E4%BB%98%E3%81%8D%E3%81%AE%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0%E3%82%92%E4%BD%9C%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003ecreateDialog()\u003c/code\u003e : 入力フォーム付きのダイアログを作る\u003c/h2\u003e\n\u003cp data-sourcepos=\"68:1-68:181\"\u003eテキストエリアやセレクトボックスなど、テキスト要素以外の独自のHTML要素を含むダイアログを作る場合は \u003ccode\u003ecreateDialog()\u003c/code\u003e を使います。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"70:1-70:22\"\u003e\n\u003cspan id=\"使用場面の例-1\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BD%BF%E7%94%A8%E5%A0%B4%E9%9D%A2%E3%81%AE%E4%BE%8B-1\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e使用場面の例\u003c/h3\u003e\n\u003cul data-sourcepos=\"72:1-75:0\"\u003e\n\u003cli data-sourcepos=\"72:1-72:65\"\u003e入力フォームを含むダイアログを表示したい。\u003c/li\u003e\n\u003cli data-sourcepos=\"73:1-73:50\"\u003e閉じる前にバリデーションしたい。\u003c/li\u003e\n\u003cli data-sourcepos=\"74:1-75:0\"\u003eカスタマイズや細かい制御がしたい。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"76:1-76:58\"\u003e\n\u003cspan id=\"実装例利用規約に同意するダイアログ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E4%BE%8B%E5%88%A9%E7%94%A8%E8%A6%8F%E7%B4%84%E3%81%AB%E5%90%8C%E6%84%8F%E3%81%99%E3%82%8B%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装例：利用規約に同意するダイアログ\u003c/h3\u003e\n\u003cp data-sourcepos=\"78:1-78:177\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F0293b473-d009-416f-89a7-43d836b8534c.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=cc83ea5b25b43127ab18a4f0f0ebd435\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F0293b473-d009-416f-89a7-43d836b8534c.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=cc83ea5b25b43127ab18a4f0f0ebd435\" alt=\"createDialogによる利用規約同意ダイアログの表示例\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F0293b473-d009-416f-89a7-43d836b8534c.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=cde9a5c49f76b108afceab29886701f1 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/0293b473-d009-416f-89a7-43d836b8534c.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"80:1-82:253\"\u003e次のコードは、レコード一覧画面を開いたときに利用規約の同意ダイアログを表示する例です。\u003cbr\u003e\nチェックボックスにチェックを入れるまでOKボタンを無効にし、未確認のまま操作できないようにしています。\u003cbr\u003e\nまた、ボタンとチェックボックスの見た目の調整に \u003ca href=\"https://cybozu.dev/ja/kintone/sdk/library/plugin-stylesheet-guide/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003e51-modern-default.css\u003c/code\u003e\u003c/a\u003e を使用しています。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"84:1-150:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003euse strict\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n  \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eevents\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.index.show\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003easync \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"c1\"\u003e// ダイアログに配置するコンテンツを作成する\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003econtainer\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ediv\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ebodyContainer\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ediv\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003ebodyContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecssText\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003emin-width:500px;padding:24px;\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003ebodyContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerHTML\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e`\n      \u0026lt;textarea id=\"terms-text\" readonly style=\"box-sizing:border-box;width:100%;height:140px;margin-bottom:16px;padding:12px;font-size:14px;\"\u0026gt;\u0026lt;/textarea\u0026gt;\n      \u0026lt;div class=\"kintoneplugin-input-checkbox\"\u0026gt;\n        \u0026lt;span class=\"kintoneplugin-input-checkbox-item\"\u0026gt;\n          \u0026lt;input type=\"checkbox\" id=\"agree-check\"\u0026gt;\n          \u0026lt;label for=\"agree-check\"\u0026gt;上記の内容に同意します\u0026lt;/label\u0026gt;\n        \u0026lt;/span\u0026gt;\n      \u0026lt;/div\u0026gt;\n    `\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003etermsTextarea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ebodyContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003equerySelector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e#terms-text\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003etermsTextarea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n      \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eこのアプリの利用にあたっては、以下の規約に同意する必要があります。\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\\n\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e\n      \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e1. 本アプリで取得した情報は、業務目的以外に使用しないこと。\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e\n      \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e2. アクセス権限のない情報へのアクセスを試みないこと。\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e\n      \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e3. 本規約は予告なく変更される場合があります。\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eagreeCheck\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ebodyContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003equerySelector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e#agree-check\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n    \u003cspan class=\"c1\"\u003e// ダイアログボタンを直接取得する方法は非推奨のDOM操作を伴うため、以下の処理はコメントアウトする\u003c/span\u003e\n    \u003cspan class=\"c1\"\u003e// const okButton = container.closest('[role=\"dialog\"]')?.querySelector('button[name=\"ok\"]');\u003c/span\u003e\n\n    \u003cspan class=\"c1\"\u003e// 代わりにカスタムボタンを設置（51-modern-default.cssに準拠）\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003efooterContainer\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ediv\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003efooterContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecssText\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003edisplay:flex;justify-content:flex-end;background-color:#fff;border-top:1px solid #e3e7e8;padding:24px;\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ebutton\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etextContent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e同意してOK\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edisabled\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eclassName\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ekintoneplugin-button-disabled\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eagreeCheck\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eaddEventListener\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003echange\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eagreed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eagreeCheck\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003echecked\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edisabled\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003eagreed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eclassName\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eagreed\u003c/span\u003e\n        \u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ekintoneplugin-button-dialog-ok\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\n        \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ekintoneplugin-button-disabled\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003efooterContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n    \u003cspan class=\"nx\"\u003econtainer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ebodyContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003efooterContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003edialog\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003ecreateDialog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n      \u003cspan class=\"na\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e利用規約への同意\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003econtainer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowOkButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowCancelButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowCloseButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\n    \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nc\"\u003ePromise\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nx\"\u003eresolve\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003eokButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eaddEventListener\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eclick\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003edialog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eclose\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n        \u003cspan class=\"nf\"\u003eresolve\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eOK\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003edialog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\n    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"152:1-152:22\"\u003e\n\u003cspan id=\"モバイル対応-1\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E5%AF%BE%E5%BF%9C-1\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eモバイル対応\u003c/h3\u003e\n\u003cp data-sourcepos=\"154:1-155:188\"\u003eモバイル版では \u003ccode\u003ekintone.mobile.createBottomSheet()\u003c/code\u003e を使います。\u003cbr\u003e\n引数・戻り値の仕様は \u003ccode\u003ecreateDialog()\u003c/code\u003e と同様で、モバイルデバイスの画面の下端に配置されるボトムシートと呼ばれるUIが提供されています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"157:1-157:83\"\u003e\n\u003cspan id=\"pc版とモバイル版でダイアログとボトムシートを出し分ける\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#pc%E7%89%88%E3%81%A8%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E7%89%88%E3%81%A7%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0%E3%81%A8%E3%83%9C%E3%83%88%E3%83%A0%E3%82%B7%E3%83%BC%E3%83%88%E3%82%92%E5%87%BA%E3%81%97%E5%88%86%E3%81%91%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ePC版とモバイル版でダイアログとボトムシートを出し分ける\u003c/h2\u003e\n\u003cp data-sourcepos=\"159:1-160:80\"\u003ePCでは \u003ccode\u003eshowConfirmDialog()\u003c/code\u003e 、モバイルでは \u003ccode\u003eshowConfirmBottomSheet()\u003c/code\u003e を使うように切り替えると、\u003cbr\u003e\n同じ確認フローをデバイスに最適化したUIで提供できます。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"162:1-162:79\"\u003e\n\u003cspan id=\"実装例デバイスに応じて確認ダイアログを出し分ける\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E4%BE%8B%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%AB%E5%BF%9C%E3%81%98%E3%81%A6%E7%A2%BA%E8%AA%8D%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0%E3%82%92%E5%87%BA%E3%81%97%E5%88%86%E3%81%91%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装例：デバイスに応じて確認ダイアログを出し分ける\u003c/h3\u003e\n\u003cp data-sourcepos=\"164:1-164:128\"\u003e次のコードは、PC版とモバイル版で確認ダイアログを出し分けるユーティリティ関数の例です。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"166:1-188:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003easync\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eshowConfirmation\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eisMobilePage\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003emobile\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowConfirmBottomSheet\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n      \u003cspan class=\"na\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowOkButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eokButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eOK\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003eshowCancelButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"na\"\u003ecancelButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eキャンセル\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n  \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowConfirmDialog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n    \u003cspan class=\"na\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n    \u003cspan class=\"na\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n    \u003cspan class=\"na\"\u003eshowOkButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n    \u003cspan class=\"na\"\u003eokButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eOK\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n    \u003cspan class=\"na\"\u003eshowCancelButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n    \u003cspan class=\"na\"\u003ecancelButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eキャンセル\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"190:1-190:122\"\u003e\u003ccode\u003ekintone.isMobilePage()\u003c/code\u003e でモバイル版かどうかを判定し、 \u003ccode\u003eshowConfirmBottomSheet()\u003c/code\u003e を呼び出します。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"192:1-192:62\"\u003e\n\u003cspan id=\"shownotification--showloading--進捗を伝える\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#shownotification--showloading--%E9%80%B2%E6%8D%97%E3%82%92%E4%BC%9D%E3%81%88%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003eshowNotification()\u003c/code\u003e / \u003ccode\u003eshowLoading()\u003c/code\u003e : 進捗を伝える\u003c/h2\u003e\n\u003cp data-sourcepos=\"194:1-195:90\"\u003e時間がかかる処理ではローディングアニメーションを表示することで、\u003cbr\u003e\nユーザーが「処理が止まってしまった」と誤解するのを防げます。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"197:1-197:103\"\u003e\n\u003cspan id=\"実装例処理中はローディングを表示し完了後に通知バナーを表示する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E4%BE%8B%E5%87%A6%E7%90%86%E4%B8%AD%E3%81%AF%E3%83%AD%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%97%E5%AE%8C%E4%BA%86%E5%BE%8C%E3%81%AB%E9%80%9A%E7%9F%A5%E3%83%90%E3%83%8A%E3%83%BC%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装例：処理中はローディングを表示し、完了後に通知バナーを表示する\u003c/h3\u003e\n\u003cp data-sourcepos=\"199:1-199:153\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F7253888f-5335-48c1-b36e-33b8cd0ce044.gif?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=22d754d98ea4a209666904a1a9916bd6\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F7253888f-5335-48c1-b36e-33b8cd0ce044.gif?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=22d754d98ea4a209666904a1a9916bd6\" alt=\"showLoadingとshowNotificationの表示例\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F7253888f-5335-48c1-b36e-33b8cd0ce044.gif?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=4f1aa95cc4f08cd6f81377d290f031a8 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/7253888f-5335-48c1-b36e-33b8cd0ce044.gif\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"201:1-201:126\"\u003e次のコードは、プロセス変更時にローディングを表示し、完了後に通知バナーを出す例です。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"203:1-226:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003euse strict\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n  \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eevents\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.detail.process.proceed\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003easync \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"k\"\u003etry\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowLoading\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eVISIBLE\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"c1\"\u003e// 時間のかかる処理（例: REST APIの呼び出し）\u003c/span\u003e\n      \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"nf\"\u003erunLongProcess\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowNotification\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eSUCCESS\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e`ステータスが「\u003c/span\u003e\u003cspan class=\"p\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estatus\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e」から「\u003c/span\u003e\u003cspan class=\"p\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003enextStatus\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e」に更新されました。`\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowNotification\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eERROR\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e更新中にエラーが発生しました。\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e更新エラー:\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003efinally\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowLoading\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eHIDDEN\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\n  \u003cspan class=\"k\"\u003easync\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003erunLongProcess\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"c1\"\u003e// 時間のかかる処理の実装\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"228:1-229:150\"\u003e\u003ccode\u003ekintone.showLoading('VISIBLE')\u003c/code\u003eでローディングを表示し、処理完了後に\u003ccode\u003ekintone.showLoading('HIDDEN')\u003c/code\u003eで非表示にします。\u003cbr\u003e\n\u003ccode\u003efinally\u003c/code\u003eブロックで非表示にすることで、エラーが発生した場合もローディング表示が残り続けるのを防げます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"231:1-231:52\"\u003e\n\u003cspan id=\"3ステップのapiを組み合わせた実装例\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%81%AEapi%E3%82%92%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%9F%E5%AE%9F%E8%A3%85%E4%BE%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3ステップのAPIを組み合わせた実装例\u003c/h2\u003e\n\u003cp data-sourcepos=\"233:1-233:145\"\u003eここまで紹介したAPIを組み合わせると、「確認→進捗→結果」の流れを1つの操作体験として実装できます。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"235:1-235:88\"\u003e\n\u003cspan id=\"実装例確認進捗結果の3ステップを使ったai質問箱アプリ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E4%BE%8B%E7%A2%BA%E8%AA%8D%E9%80%B2%E6%8D%97%E7%B5%90%E6%9E%9C%E3%81%AE3%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9Fai%E8%B3%AA%E5%95%8F%E7%AE%B1%E3%82%A2%E3%83%97%E3%83%AA\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装例：確認→進捗→結果の3ステップを使ったAI質問箱アプリ\u003c/h3\u003e\n\u003cp data-sourcepos=\"237:1-237:195\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F1295c2b7-6966-4eaa-a8bf-ceedc7c07ab2.gif?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=93ebe00c05ec15af09a3b1bcdbc09dbd\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F1295c2b7-6966-4eaa-a8bf-ceedc7c07ab2.gif?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=93ebe00c05ec15af09a3b1bcdbc09dbd\" alt=\"確認→進捗→結果の3ステップを使ったAI質問箱アプリの表示例\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F68679%2F1295c2b7-6966-4eaa-a8bf-ceedc7c07ab2.gif?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=c9efb93b16cb936ae57d94b554721680 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/1295c2b7-6966-4eaa-a8bf-ceedc7c07ab2.gif\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"239:1-240:130\"\u003e質問箱アプリの編集画面で「AIで回答する」ボタンを押すと、\u003cbr\u003e\n確認ダイアログを表示し、OKならAI（時間がかかる処理）を呼び出して回答欄を更新する例です。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"242:1-298:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003euse strict\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n  \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eevents\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.edit.show\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003espaceElement\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003egetSpaceElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eanswerButton\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003espaceElement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eanswerButton\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ebutton\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eanswerButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etextContent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eAIで回答を生成する\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eanswerButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eclassName\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ekintoneplugin-button-normal\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eanswerButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecssText\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003emargin:8px;\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003eanswerButton\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eonclick\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003easync \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n      \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003equestion\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e質問内容\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n      \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowConfirmDialog\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n        \u003cspan class=\"na\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eAIで回答を生成\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n        \u003cspan class=\"na\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e質問の回答をAIで生成します。よろしいですか？\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n        \u003cspan class=\"na\"\u003eshowOkButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n        \u003cspan class=\"na\"\u003eokButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e生成する\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n        \u003cspan class=\"na\"\u003eshowCancelButton\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n        \u003cspan class=\"na\"\u003ecancelButtonText\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eキャンセル\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\n      \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e!==\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eOK\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n      \u003cspan class=\"k\"\u003etry\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowLoading\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eVISIBLE\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n        \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"nf\"\u003egenerateAnswer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003equestion\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowNotification\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eSUCCESS\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e回答を生成しました。内容を確認して保存してください。\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowNotification\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eERROR\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e回答の生成中にエラーが発生しました。\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003efinally\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eshowLoading\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eHIDDEN\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003espaceElement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eappendChild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eanswerButton\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\n  \u003cspan class=\"k\"\u003easync\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003egenerateAnswer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003equestion\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"c1\"\u003e// AIへのリクエスト処理\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eproxy\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n      \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ehttps://ai.example.com/generate\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ePOST\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eContent-Type\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapplication/json\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n      \u003cspan class=\"nx\"\u003eJSON\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003estringify\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e \u003cspan class=\"na\"\u003equestion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003equestion\u003c/span\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003eanswer\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eJSON\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// AIから取得した回答を入れる\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e回答欄\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eanswer\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eapp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"300:1-300:231\"\u003e確認ダイアログで実行可否を確認し、進捗中はローディングを表示し、最後に結果を通知バナーに表示することで、ユーザーにとって分かりやすい操作フローを作れます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"302:1-302:12\"\u003e\n\u003cspan id=\"まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまとめ\u003c/h2\u003e\n\u003cp data-sourcepos=\"304:1-304:148\"\u003e本記事では、確認ダイアログと通知バナーAPIを使った「確認→進捗→結果」の3ステップ設計を紹介しました。\u003c/p\u003e\n\u003cp data-sourcepos=\"306:1-306:72\"\u003e最後に、用途ごとの使い分けをフローで整理します。\u003c/p\u003e\n\u003cimg src=\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXMtYXNjaWkiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U3R5bGVUeXBlPSJ0ZXh0L2NzcyIgaGVpZ2h0PSI2NjVweCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSIgc3R5bGU9IndpZHRoOjc5NXB4O2hlaWdodDo2NjVweDtiYWNrZ3JvdW5kOiNGRkZGRkY7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA3OTUgNjY1IiB3aWR0aD0iNzk1cHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48ZWxsaXBzZSBjeD0iMzAwLjUiIGN5PSIyMCIgZmlsbD0iIzIyMjIyMiIgcng9IjEwIiByeT0iMTAiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MS4wOyIvPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iMjE1Ljk0NDgiIHN0eWxlPSJzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS41OyIgd2lkdGg9Ijc2OC41IiB4PSIxNS41IiB5PSI0MCIvPjxwYXRoIGQ9Ik0xNTMuNSw0MCBMMTUzLjUsNDkuMjk2OSBMMTQzLjUsNTkuMjk2OSBMMTUuNSw1OS4yOTY5ICIgZmlsbD0ibm9uZSIgc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjU7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTI4IiB4PSIxOC41IiB5PSI1My45OTUxIj4mIzkzMTI7ICYjMzA5MDY7JiMzNTQ2OTsgLSAmIzEyNDgwOyYjMTI0NTI7JiMxMjQ1MDsmIzEyNTI1OyYjMTI0NjQ7PC90ZXh0Pjxwb2x5Z29uIGZpbGw9IiNGMUYxRjEiIHBvaW50cz0iMjE1LDc2LjI5NjksMzg2LDc2LjI5NjksMzk4LDg4LjI5NjksMzg2LDEwMC4yOTY5LDIxNSwxMDAuMjk2OSwyMDMsODguMjk2OSwyMTUsNzYuMjk2OSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTcxIiB4PSIyMTUiIHk9IjkyLjEwNSI+JiMxMjQ4MDsmIzEyNDUyOyYjMTI0NTA7JiMxMjUyNTsmIzEyNDY0OyYjMTIzOTU7JiMyMDgzNzsmIzIxMTQ3OyYjMTI1MDE7JiMxMjQ1NzsmIzEyNTQwOyYjMTI1MTI7JiMxMjM2NDsmIzI0NTE3OyYjMzUyMDE7PzwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIyMCIgeD0iMTgzIiB5PSI4NS43MDI2Ij55ZXM8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iOTIiIHg9IjM5OCIgeT0iODUuNzAyNiI+bm8gLSAmIzEyNDg2OyYjMTI0NjE7JiMxMjQ3MzsmIzEyNDg4OyYjMTIzOTg7JiMxMjQxNTs8L3RleHQ+PHJlY3QgZmlsbD0iI0Q2RUFGOCIgaGVpZ2h0PSI0Ny45Mzc1IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjI0OSIgeD0iMzIiIHk9IjExMC4yOTY5Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTQxIiB4PSI0MiIgeT0iMTMxLjQzNTUiPmtpbnRvbmUuY3JlYXRlRGlhbG9nKCk8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjI5IiB4PSI0MiIgeT0iMTQ1LjQwNDMiPmtpbnRvbmUubW9iaWxlLmNyZWF0ZUJvdHRvbVNoZWV0KCk8L3RleHQ+PHBhdGggZD0iTTYwOCwxMTQuMTMyOCBMNjA4LDEzMC4yNjU2IEw1ODgsMTM0LjI2NTYgTDYwOCwxMzguMjY1NiBMNjA4LDE1NC4zOTg0IEEwLDAgMCAwIDAgNjA4LDE1NC4zOTg0IEw3NzIsMTU0LjM5ODQgQTAsMCAwIDAgMCA3NzIsMTU0LjM5ODQgTDc3MiwxMjQuMTMyOCBMNzYyLDExNC4xMzI4IEw2MDgsMTE0LjEzMjggQTAsMCAwIDAgMCA2MDgsMTE0LjEzMjggIiBmaWxsPSIjRkVGRkREIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiLz48cGF0aCBkPSJNNzYyLDExNC4xMzI4IEw3NjIsMTI0LjEzMjggTDc3MiwxMjQuMTMyOCBMNzYyLDExNC4xMzI4ICIgZmlsbD0iI0ZFRkZERCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTI2IiB4PSI2MTQiIHk9IjEzMS4xOTk3Ij4mIzEyMzAwO09LLyYjMTI0NjE7JiMxMjUxNTsmIzEyNTMxOyYjMTI0NzU7JiMxMjUyMzsmIzEyMzAxOyYjMTIzOTE7PC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjE0MyIgeD0iNjE0IiB5PSIxNDYuMzMyNSI+JiMzMDkwNjsmIzM1NDY5OyYjMTIzNzc7JiMxMjQyNzsmIzEyMzg0OyYjMTIzNjk7JiMxMjM5NDsmIzEyNDI1OyYjMTIzNzE7JiMxMjM4NTsmIzEyNDI1OzwvdGV4dD48cmVjdCBmaWxsPSIjRDZFQUY4IiBoZWlnaHQ9IjQ3LjkzNzUiIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMjg3IiB4PSIzMDEiIHk9IjExMC4yOTY5Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTc5IiB4PSIzMTEiIHk9IjEzMS40MzU1Ij5raW50b25lLnNob3dDb25maXJtRGlhbG9nKCk8L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjY3IiB4PSIzMTEiIHk9IjE0NS40MDQzIj5raW50b25lLm1vYmlsZS5zaG93Q29uZmlybUJvdHRvbVNoZWV0KCk8L3RleHQ+PHBvbHlnb24gZmlsbD0iI0YxRjFGMSIgcG9pbnRzPSIzMDAuNSwxNjQuMjM0NCwzMTIuNSwxNzYuMjM0NCwzMDAuNSwxODguMjM0NCwyODguNSwxNzYuMjM0NCwzMDAuNSwxNjQuMjM0NCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7Ii8+PHBvbHlnb24gZmlsbD0iI0YxRjFGMSIgcG9pbnRzPSIyNzMsMjA4LjIzNDQsMzI4LDIwOC4yMzQ0LDM0MCwyMjAuMjM0NCwzMjgsMjMyLjIzNDQsMjczLDIzMi4yMzQ0LDI2MSwyMjAuMjM0NCwyNzMsMjA4LjIzNDQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjIwIiB4PSIzMDQuNSIgeT0iMjQyLjQ0NDgiPnllczwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI1NSIgeD0iMjczIiB5PSIyMjQuMDQyNSI+T0smIzEyNDM0OyYjMzY5ODQ7JiMyNTI0Njs/PC90ZXh0Pjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjExIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjU1IiB4PSIzNDAiIHk9IjIxNy42NDAxIj4mIzEyNDYxOyYjMTI1MTU7JiMxMjUzMTsmIzEyNDc1OyYjMTI1MjM7PC90ZXh0PjxlbGxpcHNlIGN4PSI0MTciIGN5PSIyMjAuMjM0NCIgZmlsbD0ibm9uZSIgcng9IjExIiByeT0iMTEiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MS4wOyIvPjxlbGxpcHNlIGN4PSI0MTciIGN5PSIyMjAuMjM0NCIgZmlsbD0iIzIyMjIyMiIgcng9IjYiIHJ5PSI2IiBzdHlsZT0ic3Ryb2tlOiMyMjIyMjI7c3Ryb2tlLXdpZHRoOjEuMDsiLz48cmVjdCBmaWxsPSJub25lIiBoZWlnaHQ9IjE5MC4yMDMxIiBzdHlsZT0ic3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuNTsiIHdpZHRoPSIyMzUiIHg9IjE4MyIgeT0iMjY1Ljk0NDgiLz48cGF0aCBkPSJNMzM1LDI2NS45NDQ4IEwzMzUsMjc1LjI0MTcgTDMyNSwyODUuMjQxNyBMMTgzLDI4NS4yNDE3ICIgZmlsbD0ibm9uZSIgc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjU7Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTQyIiB4PSIxODYiIHk9IjI3OS45Mzk5Ij4mIzkzMTM7ICYjMzY5MTQ7JiMyNTQzMTsgLSAmIzEyNTI1OyYjMTI1NDA7JiMxMjQ4NzsmIzEyNDUxOyYjMTI1MzE7JiMxMjQ2NDs8L3RleHQ+PHJlY3QgZmlsbD0iI0ZFRjlFNyIgaGVpZ2h0PSIzMy45Njg4IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjIxMiIgeD0iMTk0LjUiIHk9IjMwMi4yNDE3Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTIiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMTkyIiB4PSIyMDQuNSIgeT0iMzIzLjM4MDQiPmtpbnRvbmUuc2hvd0xvYWRpbmcoJ1ZJU0lCTEUnKTwvdGV4dD48cmVjdCBmaWxsPSIjRjFGMUYxIiBoZWlnaHQ9IjMzLjk2ODgiIHJ4PSIxMi41IiByeT0iMTIuNSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDowLjU7IiB3aWR0aD0iMTkyIiB4PSIyMDQuNSIgeT0iMzU2LjIxMDQiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNzIiIHg9IjIxNC41IiB5PSIzNzcuMzQ5MSI+JiMyMDk2NjsmIzI5NzAyOyYjMjM0NTU7JiMzNDg5MjsmIzY1Mjg4O0pTIEFQSSAvIFJFU1QgQVBJJiM2NTI4OTs8L3RleHQ+PHJlY3QgZmlsbD0iI0ZFRjlFNyIgaGVpZ2h0PSIzMy45Njg4IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjIxNSIgeD0iMTkzIiB5PSI0MTAuMTc5MiIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjE5NSIgeD0iMjAzIiB5PSI0MzEuMzE3OSI+a2ludG9uZS5zaG93TG9hZGluZygnSElEREVOJyk8L3RleHQ+PHJlY3QgZmlsbD0ibm9uZSIgaGVpZ2h0PSIxNDYuMjY1NiIgc3R5bGU9InN0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjU7IiB3aWR0aD0iNTc0LjUiIHg9IjExIiB5PSI0NjYuMTQ3OSIvPjxwYXRoIGQ9Ik0xNDksNDY2LjE0NzkgTDE0OSw0NzUuNDQ0OCBMMTM5LDQ4NS40NDQ4IEwxMSw0ODUuNDQ0OCAiIGZpbGw9Im5vbmUiIHN0eWxlPSJzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS41OyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjE0IiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjEyOCIgeD0iMTQiIHk9IjQ4MC4xNDMxIj4mIzkzMTQ7ICYjMzIwODA7JiMyNjUyNDsgLSAmIzM2ODkwOyYjMzA2OTM7JiMxMjQ5NjsmIzEyNDkwOyYjMTI1NDA7PC90ZXh0Pjxwb2x5Z29uIGZpbGw9IiNGMUYxRjEiIHBvaW50cz0iMjcwLDUwMi40NDQ4LDMzMSw1MDIuNDQ0OCwzNDMsNTE0LjQ0NDgsMzMxLDUyNi40NDQ4LDI3MCw1MjYuNDQ0OCwyNTgsNTE0LjQ0NDgsMjcwLDUwMi40NDQ4IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSI2MSIgeD0iMjcwIiB5PSI1MTguMjUyOSI+JiMyMDk2NjsmIzI5NzAyOyYjMTIzNjQ7JiMyNTEwNDsmIzIxMTUxOz88L3RleHQ+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTEiIGxlbmd0aEFkanVzdD0ic3BhY2luZyIgdGV4dExlbmd0aD0iMjAiIHg9IjIzOCIgeT0iNTExLjg1MDYiPnllczwvdGV4dD48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMSIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIxNCIgeD0iMzQzIiB5PSI1MTEuODUwNiI+bm88L3RleHQ+PHJlY3QgZmlsbD0iI0Q1RjVFMyIgaGVpZ2h0PSIzMy45Njg4IiByeD0iMTIuNSIgcnk9IjEyLjUiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MC41OyIgd2lkdGg9IjI2NyIgeD0iMjcuNSIgeT0iNTM2LjQ0NDgiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMiIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nIiB0ZXh0TGVuZ3RoPSIyNDciIHg9IjM3LjUiIHk9IjU1Ny41ODM1Ij5raW50b25lLnNob3dOb3RpZmljYXRpb24oJ1NVQ0NFU1MnLCAuLi4pPC90ZXh0PjxyZWN0IGZpbGw9IiNGQURCRDgiIGhlaWdodD0iMzMuOTY4OCIgcng9IjEyLjUiIHJ5PSIxMi41IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiIHdpZHRoPSIyNTEiIHg9IjMxNC41IiB5PSI1MzYuNDQ0OCIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmciIHRleHRMZW5ndGg9IjIzMSIgeD0iMzI0LjUiIHk9IjU1Ny41ODM1Ij5raW50b25lLnNob3dOb3RpZmljYXRpb24oJ0VSUk9SJywgLi4uKTwvdGV4dD48cG9seWdvbiBmaWxsPSIjRjFGMUYxIiBwb2ludHM9IjMwMC41LDU3Ni40MTM2LDMxMi41LDU4OC40MTM2LDMwMC41LDYwMC40MTM2LDI4OC41LDU4OC40MTM2LDMwMC41LDU3Ni40MTM2IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjAuNTsiLz48ZWxsaXBzZSBjeD0iMzAwLjUiIGN5PSI2NDMuNDEzNiIgZmlsbD0ibm9uZSIgcng9IjExIiByeT0iMTEiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MS4wOyIvPjxlbGxpcHNlIGN4PSIzMDAuNSIgY3k9IjY0My40MTM2IiBmaWxsPSIjMjIyMjIyIiByeD0iNiIgcnk9IjYiIHN0eWxlPSJzdHJva2U6IzIyMjIyMjtzdHJva2Utd2lkdGg6MS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjIwMyIgeDI9IjE1Ni41IiB5MT0iODguMjk2OSIgeTI9Ijg4LjI5NjkiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSIxNTYuNSIgeDI9IjE1Ni41IiB5MT0iODguMjk2OSIgeTI9IjExMC4yOTY5Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIxNTIuNSwxMDAuMjk2OSwxNTYuNSwxMTAuMjk2OSwxNjAuNSwxMDAuMjk2OSwxNTYuNSwxMDQuMjk2OSIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iMzk4IiB4Mj0iNDQ0LjUiIHkxPSI4OC4yOTY5IiB5Mj0iODguMjk2OSIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjQ0NC41IiB4Mj0iNDQ0LjUiIHkxPSI4OC4yOTY5IiB5Mj0iMTEwLjI5NjkiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjQ0MC41LDEwMC4yOTY5LDQ0NC41LDExMC4yOTY5LDQ0OC41LDEwMC4yOTY5LDQ0NC41LDEwNC4yOTY5IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSIxNTYuNSIgeDI9IjE1Ni41IiB5MT0iMTU4LjIzNDQiIHkyPSIxNzYuMjM0NCIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjE1Ni41IiB4Mj0iMjg4LjUiIHkxPSIxNzYuMjM0NCIgeTI9IjE3Ni4yMzQ0Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyNzguNSwxNzIuMjM0NCwyODguNSwxNzYuMjM0NCwyNzguNSwxODAuMjM0NCwyODIuNSwxNzYuMjM0NCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iNDQ0LjUiIHgyPSI0NDQuNSIgeTE9IjE1OC4yMzQ0IiB5Mj0iMTc2LjIzNDQiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSI0NDQuNSIgeDI9IjMxMi41IiB5MT0iMTc2LjIzNDQiIHkyPSIxNzYuMjM0NCIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMzIyLjUsMTcyLjIzNDQsMzEyLjUsMTc2LjIzNDQsMzIyLjUsMTgwLjIzNDQsMzE4LjUsMTc2LjIzNDQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjMwMC41IiB4Mj0iMzAwLjUiIHkxPSIyMzIuMjM0NCIgeTI9IjMwMi4yNDE3Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyOTYuNSwyOTIuMjQxNywzMDAuNSwzMDIuMjQxNywzMDQuNSwyOTIuMjQxNywzMDAuNSwyOTYuMjQxNyIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iMzQwIiB4Mj0iNDA2IiB5MT0iMjIwLjIzNDQiIHkyPSIyMjAuMjM0NCIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMzk2LDIxNi4yMzQ0LDQwNiwyMjAuMjM0NCwzOTYsMjI0LjIzNDQsNDAwLDIyMC4yMzQ0IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSIzMDAuNSIgeDI9IjMwMC41IiB5MT0iMTg4LjIzNDQiIHkyPSIyMDguMjM0NCIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMjk2LjUsMTk4LjIzNDQsMzAwLjUsMjA4LjIzNDQsMzA0LjUsMTk4LjIzNDQsMzAwLjUsMjAyLjIzNDQiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjMwMC41IiB4Mj0iMzAwLjUiIHkxPSIzMCIgeTI9Ijc2LjI5NjkiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjI5Ni41LDY2LjI5NjksMzAwLjUsNzYuMjk2OSwzMDQuNSw2Ni4yOTY5LDMwMC41LDcwLjI5NjkiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjMwMC41IiB4Mj0iMzAwLjUiIHkxPSIzMzYuMjEwNCIgeTI9IjM1Ni4yMTA0Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyOTYuNSwzNDYuMjEwNCwzMDAuNSwzNTYuMjEwNCwzMDQuNSwzNDYuMjEwNCwzMDAuNSwzNTAuMjEwNCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iMzAwLjUiIHgyPSIzMDAuNSIgeTE9IjM5MC4xNzkyIiB5Mj0iNDEwLjE3OTIiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjI5Ni41LDQwMC4xNzkyLDMwMC41LDQxMC4xNzkyLDMwNC41LDQwMC4xNzkyLDMwMC41LDQwNC4xNzkyIiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSIyNTgiIHgyPSIxNjEiIHkxPSI1MTQuNDQ0OCIgeTI9IjUxNC40NDQ4Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iMTYxIiB4Mj0iMTYxIiB5MT0iNTE0LjQ0NDgiIHkyPSI1MzYuNDQ0OCIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMTU3LDUyNi40NDQ4LDE2MSw1MzYuNDQ0OCwxNjUsNTI2LjQ0NDgsMTYxLDUzMC40NDQ4IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSIzNDMiIHgyPSI0NDAiIHkxPSI1MTQuNDQ0OCIgeTI9IjUxNC40NDQ4Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iNDQwIiB4Mj0iNDQwIiB5MT0iNTE0LjQ0NDgiIHkyPSI1MzYuNDQ0OCIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iNDM2LDUyNi40NDQ4LDQ0MCw1MzYuNDQ0OCw0NDQsNTI2LjQ0NDgsNDQwLDUzMC40NDQ4IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiIHgxPSIxNjEiIHgyPSIxNjEiIHkxPSI1NzAuNDEzNiIgeTI9IjU4OC40MTM2Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iMTYxIiB4Mj0iMjg4LjUiIHkxPSI1ODguNDEzNiIgeTI9IjU4OC40MTM2Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyNzguNSw1ODQuNDEzNiwyODguNSw1ODguNDEzNiwyNzguNSw1OTIuNDEzNiwyODIuNSw1ODguNDEzNiIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iNDQwIiB4Mj0iNDQwIiB5MT0iNTcwLjQxMzYiIHkyPSI1ODguNDEzNiIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjQ0MCIgeDI9IjMxMi41IiB5MT0iNTg4LjQxMzYiIHkyPSI1ODguNDEzNiIvPjxwb2x5Z29uIGZpbGw9IiMxODE4MTgiIHBvaW50cz0iMzIyLjUsNTg0LjQxMzYsMzEyLjUsNTg4LjQxMzYsMzIyLjUsNTkyLjQxMzYsMzE4LjUsNTg4LjQxMzYiIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6IzE4MTgxODtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjMwMC41IiB4Mj0iMzAwLjUiIHkxPSI0NDQuMTQ3OSIgeTI9IjUwMi40NDQ4Ii8+PHBvbHlnb24gZmlsbD0iIzE4MTgxOCIgcG9pbnRzPSIyOTYuNSw0OTIuNDQ0OCwzMDAuNSw1MDIuNDQ0OCwzMDQuNSw0OTIuNDQ0OCwzMDAuNSw0OTYuNDQ0OCIgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTojMTgxODE4O3N0cm9rZS13aWR0aDoxLjA7IiB4MT0iMzAwLjUiIHgyPSIzMDAuNSIgeTE9IjYwMC40MTM2IiB5Mj0iNjMyLjQxMzYiLz48cG9seWdvbiBmaWxsPSIjMTgxODE4IiBwb2ludHM9IjI5Ni41LDYyMi40MTM2LDMwMC41LDYzMi40MTM2LDMwNC41LDYyMi40MTM2LDMwMC41LDYyNi40MTM2IiBzdHlsZT0ic3Ryb2tlOiMxODE4MTg7c3Ryb2tlLXdpZHRoOjEuMDsiLz48IS0tU1JDPVtYTDlUUW5EMTU3dEZoeFlxM3pjMGZXekloVWMzOURhRG5mUDZpa2ZKTnpQc2FtbWNDb0t4ODI5MlBlVXNRS21XTEtKeWU2Y1loVFpJOGVoV0h3M19uU2xjdXdiX21UcmllYXNpLVo5U3Zpd1NTLXV2ci05NmFHUzJRLXY5RTY0S2Zkdml4cUF0elFydEs4RUJXQkE0emJrcU1vWUZxRnVtMUd5MzAyRzNvYUczblE2cGxrVEtOZzV5WGxQeGI2c0trb1lncGlid1JyelMybTdGY0hJSzF3T0xTVzQwZmpOQk1aR241eGI3QTZWSzNBeUtKT0VSQVo3b0JBazRia2RlbGkza2Fsb2U3TUVTaXVBVUNxc2tYRVBUNzNEbGNRMUdEWDJ3V1JRaHYybEFDZWZaNTJWZDRyYXZUWl9FUThPSzJ0emJFX0ZjM3FlMG9oVzlIUEJEeUdYV2dQZlFjRjY4dkhrS2R6My1abDhHSXBLS3h2UWZSb0FBNXNXX0hrNndpT3RZMEVxajU0ekhERHQyY3Uya2Fhbld3NmJnMFVxZFZWNmJLemNQVENvVlQ4QjhkejNZUkVxTnFnRTlBOWxHQnR0aXI5dUY3M2VRbkJBOWpXeW5KN0N3ZUlNa1FiVjY3NWZhbllnWE1JTHU5d2FkT3VqUVMzMXhuRGRTeHpPdGRFRDZocmF6UlBUbHcxMnpjT0dQSTZsd0JReXlSTV9EX21fblViOUxqSUtGUzU5aDJ4Z1Z3dnNUcnd4TVZrYmJqeDY3aWV3b3VlaC1sTlEtMGRVbkVrTXdLc2NTanJZcFlMZGpxWFp0NGtDYUdyT0NacVc5d2hWWlNLdE5XblNXNzB3RmhUNEc4SDVMTy1oU0ZuMnFUM2dMRmxqX1BCcU5uS3kwXS0tPjwvZz48L3N2Zz4=\" loading=\"lazy\"\u003e\n\u003cp data-sourcepos=\"344:1-344:96\"\u003eダイアログAPIの使い分けについては、次の記事も参考にしてください。\u003c/p\u003e\n\u003cp data-sourcepos=\"346:1-346:162\"\u003e\u003ciframe id=\"qiita-embed-content__0ecf043f0318b09a7eacd96b2e398d4b\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__0ecf043f0318b09a7eacd96b2e398d4b\" data-content=\"https%3A%2F%2Fcybozu.dev%2Fja%2Fkintone%2Ftips%2Fdevelopment%2Fcustomize%2Fdevelopment-know-how%2Fdialog-api-comparison%2F%3Futm_source%3Dqiita%26utm_medium%3Dreferral%26utm_campaign%3Dorg_article\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\"\u003e\n\u003c/iframe\u003e\n\u003c/p\u003e\n\u003ch2 data-sourcepos=\"348:1-348:15\"\u003e\n\u003cspan id=\"おわりに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eおわりに\u003c/h2\u003e\n\u003cp data-sourcepos=\"350:1-350:141\"\u003e確認ダイアログや通知バナーAPIを組み合わせるだけでも、カスタマイズの使い勝手は大きく変わります。\u003c/p\u003e\n\u003cp data-sourcepos=\"352:1-353:76\"\u003eまとめのフロー図を参考に「ユーザー対話型カスタマイズ」を意識して、\u003cbr\u003e\nご自身のkintoneカスタマイズにも活用してみてください。\u003c/p\u003e\n\u003cdiv data-sourcepos=\"355:1-357:3\" class=\"note warn\"\u003e\n\u003cspan class=\"fa fa-fw fa-exclamation-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"356:1-356:75\"\u003eこの記事は、2026年4月版kintoneで動作を確認しています。\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 data-sourcepos=\"359:1-359:18\"\u003e\n\u003cspan id=\"参考リンク\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e参考リンク\u003c/h2\u003e\n\u003cul data-sourcepos=\"361:1-367:211\"\u003e\n\u003cli data-sourcepos=\"361:1-361:201\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-dialog/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e確認ダイアログを表示する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"362:1-362:189\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-dialog/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003eダイアログを作成する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"363:1-363:208\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-notification/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e画面上部にメッセージを表示する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"364:1-364:191\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-loading/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003eローディングを表示する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"365:1-365:209\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-bottomsheet/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003e確認ボトムシートを表示する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"366:1-366:197\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-bottomsheet/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003eボトムシートを作成する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"367:1-367:211\"\u003e\u003ca href=\"https://cybozu.dev/ja/kintone/docs/js-api/kintone/is-mobile-page/?utm_source=qiita\u0026amp;utm_medium=referral\u0026amp;utm_campaign=org_article\" rel=\"nofollow noopener\" target=\"_blank\"\u003eモバイル版の画面かどうかを取得する - cybozu developer network\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","body":"\n## はじめに\n\nkintoneのカスタマイズで「この処理、実行前にユーザーへ確認を取りたい」と感じたことはありませんか？\n\n実際、kintoneアプリでは「画面上の操作だけでは把握しきれない処理」や  \n「一括登録・一括削除・ステータス変更など、取り消せない処理」を実装することがあります。\n\nこうした処理では、実行前にユーザーへ確認を取ることがUX設計として重要です。  \n確認ダイアログを表示することで、処理の内容をユーザーの同意を得たうえで実行でき、誤操作のリスクを抑えられます。\n\n2025年9月〜2026年3月にかけて、kintone JavaScript APIでは  \n[`createDialog()`](https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-dialog/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)、[`showConfirmDialog()`](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-dialog/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)、[`showNotification()`](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-notification/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)、[`showLoading()`](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-loading/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)、  \n[`createBottomSheet()`](https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-bottomsheet/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)、[`showConfirmBottomSheet()`](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-bottomsheet/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)  \nといったダイアログ・通知バナー系のAPIが新たに追加されました。\n\n本記事ではこれらのAPIを使って、ユーザーに確認・進捗・結果を伝えながら、  \n処理を進める「ユーザー対話型カスタマイズ」の実装方法を解説します。\n\nまずは、最もシンプルに確認ダイアログを導入できる方法から見ていきましょう。\n\n## `showConfirmDialog()` : 確認ダイアログを表示する\n\n「OK/キャンセル」で確認するだけなら、 `showConfirmDialog()` が適しています。\n\n### 使用場面の例\n\n- ステータス変更前に確認がしたい。\n- 重要なアクションを実行する前に確認がしたい。\n- シンプルにテキストのみの確認がしたい。\n\n### 実装例：ステータス変更前の確認\n\n![showConfirmDialogによるステータス変更確認ダイアログの表示例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/81ac93e7-39f6-4c26-a913-a4e850f84916.png)\n\n次のコードは、プロセス管理のステータス変更前に確認ダイアログを表示する例です。\n\n```javascript\n(() =\u003e {\n  'use strict';\n\n  kintone.events.on('app.record.detail.process.proceed', async (event) =\u003e {\n    const result = await kintone.showConfirmDialog({\n      title: 'ステータス変更の確認',\n      body: 'ステータスを変更します。よろしいですか？',\n      showOkButton: true,\n      okButtonText: '変更する',\n      showCancelButton: true,\n      cancelButtonText: 'キャンセル',\n      showCloseButton: true\n    });\n\n    if (result !== 'OK') {\n      event.error = 'ステータス変更がキャンセルされました。';\n    }\n    return event;\n  });\n})();\n```\n\n### モバイル対応\n\nモバイル版では `kintone.mobile.showConfirmBottomSheet()` を使います。  \n引数・戻り値の仕様は `showConfirmDialog()` と同様で、モバイルデバイスの画面の下端に配置されるボトムシートと呼ばれるUIが提供されています。\n\n## `createDialog()` : 入力フォーム付きのダイアログを作る\n\nテキストエリアやセレクトボックスなど、テキスト要素以外の独自のHTML要素を含むダイアログを作る場合は `createDialog()` を使います。\n\n### 使用場面の例\n\n- 入力フォームを含むダイアログを表示したい。\n- 閉じる前にバリデーションしたい。\n- カスタマイズや細かい制御がしたい。\n\n### 実装例：利用規約に同意するダイアログ\n\n![createDialogによる利用規約同意ダイアログの表示例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/0293b473-d009-416f-89a7-43d836b8534c.png)\n\n次のコードは、レコード一覧画面を開いたときに利用規約の同意ダイアログを表示する例です。\nチェックボックスにチェックを入れるまでOKボタンを無効にし、未確認のまま操作できないようにしています。\nまた、ボタンとチェックボックスの見た目の調整に [`51-modern-default.css`](https://cybozu.dev/ja/kintone/sdk/library/plugin-stylesheet-guide/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article) を使用しています。\n\n```javascript\n(() =\u003e {\n  'use strict';\n\n  kintone.events.on('app.record.index.show', async (event) =\u003e {\n    // ダイアログに配置するコンテンツを作成する\n    const container = document.createElement('div');\n    const bodyContainer = document.createElement('div');\n    bodyContainer.style.cssText = 'min-width:500px;padding:24px;';\n    bodyContainer.innerHTML = `\n      \u003ctextarea id=\"terms-text\" readonly style=\"box-sizing:border-box;width:100%;height:140px;margin-bottom:16px;padding:12px;font-size:14px;\"\u003e\u003c/textarea\u003e\n      \u003cdiv class=\"kintoneplugin-input-checkbox\"\u003e\n        \u003cspan class=\"kintoneplugin-input-checkbox-item\"\u003e\n          \u003cinput type=\"checkbox\" id=\"agree-check\"\u003e\n          \u003clabel for=\"agree-check\"\u003e上記の内容に同意します\u003c/label\u003e\n        \u003c/span\u003e\n      \u003c/div\u003e\n    `;\n    const termsTextarea = bodyContainer.querySelector('#terms-text');\n    termsTextarea.value =\n      'このアプリの利用にあたっては、以下の規約に同意する必要があります。\\n\\n' +\n      '1. 本アプリで取得した情報は、業務目的以外に使用しないこと。\\n' +\n      '2. アクセス権限のない情報へのアクセスを試みないこと。\\n' +\n      '3. 本規約は予告なく変更される場合があります。';\n    const agreeCheck = bodyContainer.querySelector('#agree-check');\n\n    // ダイアログボタンを直接取得する方法は非推奨のDOM操作を伴うため、以下の処理はコメントアウトする\n    // const okButton = container.closest('[role=\"dialog\"]')?.querySelector('button[name=\"ok\"]');\n\n    // 代わりにカスタムボタンを設置（51-modern-default.cssに準拠）\n    const footerContainer = document.createElement('div');\n    footerContainer.style.cssText = 'display:flex;justify-content:flex-end;background-color:#fff;border-top:1px solid #e3e7e8;padding:24px;';\n    const okButton = document.createElement('button');\n    okButton.textContent = '同意してOK';\n    okButton.disabled = true;\n    okButton.className = 'kintoneplugin-button-disabled';\n    agreeCheck.addEventListener('change', () =\u003e {\n      const agreed = agreeCheck.checked;\n      okButton.disabled = !agreed;\n      okButton.className = agreed\n        ? 'kintoneplugin-button-dialog-ok'\n        : 'kintoneplugin-button-disabled';\n    });\n    footerContainer.append(okButton);\n\n    container.append(bodyContainer, footerContainer);\n\n    const dialog = await kintone.createDialog({\n      title: '利用規約への同意',\n      body: container,\n      showOkButton: false,\n      showCancelButton: false,\n      showCloseButton: false\n    });\n\n    await new Promise((resolve) =\u003e {\n      okButton.addEventListener('click', () =\u003e {\n        dialog.close();\n        resolve('OK');\n      });\n      dialog.show();\n    });\n\n    return event;\n  });\n})();\n```\n\n### モバイル対応\n\nモバイル版では `kintone.mobile.createBottomSheet()` を使います。\n引数・戻り値の仕様は `createDialog()` と同様で、モバイルデバイスの画面の下端に配置されるボトムシートと呼ばれるUIが提供されています。\n\n## PC版とモバイル版でダイアログとボトムシートを出し分ける\n\nPCでは `showConfirmDialog()` 、モバイルでは `showConfirmBottomSheet()` を使うように切り替えると、\n同じ確認フローをデバイスに最適化したUIで提供できます。\n\n### 実装例：デバイスに応じて確認ダイアログを出し分ける\n\n次のコードは、PC版とモバイル版で確認ダイアログを出し分けるユーティリティ関数の例です。\n\n```javascript\nasync function showConfirmation(title, message) {\n  if (kintone.isMobilePage()) {\n    return kintone.mobile.showConfirmBottomSheet({\n      title: title,\n      body: message,\n      showOkButton: true,\n      okButtonText: 'OK',\n      showCancelButton: true,\n      cancelButtonText: 'キャンセル'\n    });\n  }\n\n  return kintone.showConfirmDialog({\n    title: title,\n    body: message,\n    showOkButton: true,\n    okButtonText: 'OK',\n    showCancelButton: true,\n    cancelButtonText: 'キャンセル'\n  });\n}\n```\n\n`kintone.isMobilePage()` でモバイル版かどうかを判定し、 `showConfirmBottomSheet()` を呼び出します。\n\n## `showNotification()` / `showLoading()` : 進捗を伝える\n\n時間がかかる処理ではローディングアニメーションを表示することで、\nユーザーが「処理が止まってしまった」と誤解するのを防げます。\n\n### 実装例：処理中はローディングを表示し、完了後に通知バナーを表示する\n\n![showLoadingとshowNotificationの表示例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/7253888f-5335-48c1-b36e-33b8cd0ce044.gif)\n\n次のコードは、プロセス変更時にローディングを表示し、完了後に通知バナーを出す例です。\n\n```javascript\n(() =\u003e {\n  'use strict';\n\n  kintone.events.on('app.record.detail.process.proceed', async (event) =\u003e {\n    try {\n      kintone.showLoading('VISIBLE');\n      // 時間のかかる処理（例: REST APIの呼び出し）\n      await runLongProcess();\n      kintone.showNotification('SUCCESS', `ステータスが「${event.status.value}」から「${event.nextStatus.value}」に更新されました。`);\n    } catch (error) {\n      kintone.showNotification('ERROR', '更新中にエラーが発生しました。');\n      console.error('更新エラー:', error);\n    } finally {\n      kintone.showLoading('HIDDEN');\n    }\n    return event;\n  });\n\n  async function runLongProcess() {\n    // 時間のかかる処理の実装\n  }\n})();\n```\n\n`kintone.showLoading('VISIBLE')`でローディングを表示し、処理完了後に`kintone.showLoading('HIDDEN')`で非表示にします。\n`finally`ブロックで非表示にすることで、エラーが発生した場合もローディング表示が残り続けるのを防げます。\n\n## 3ステップのAPIを組み合わせた実装例\n\nここまで紹介したAPIを組み合わせると、「確認→進捗→結果」の流れを1つの操作体験として実装できます。\n\n### 実装例：確認→進捗→結果の3ステップを使ったAI質問箱アプリ\n\n![確認→進捗→結果の3ステップを使ったAI質問箱アプリの表示例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/1295c2b7-6966-4eaa-a8bf-ceedc7c07ab2.gif)\n\n質問箱アプリの編集画面で「AIで回答する」ボタンを押すと、\n確認ダイアログを表示し、OKならAI（時間がかかる処理）を呼び出して回答欄を更新する例です。\n\n```javascript\n(() =\u003e {\n  'use strict';\n\n  kintone.events.on('app.record.edit.show', (event) =\u003e {\n    const spaceElement = kintone.app.record.getSpaceElement('answerButton');\n    if (!spaceElement) return event;\n\n    const answerButton = document.createElement('button');\n    answerButton.textContent = 'AIで回答を生成する';\n    answerButton.className = 'kintoneplugin-button-normal';\n    answerButton.style.cssText = 'margin:8px;';\n    answerButton.onclick = async () =\u003e {\n      const record = kintone.app.record.get();\n      const question = record.record['質問内容'].value;\n\n      const result = await kintone.showConfirmDialog({\n        title: 'AIで回答を生成',\n        body: '質問の回答をAIで生成します。よろしいですか？',\n        showOkButton: true,\n        okButtonText: '生成する',\n        showCancelButton: true,\n        cancelButtonText: 'キャンセル'\n      });\n\n      if (result !== 'OK') return;\n\n      try {\n        kintone.showLoading('VISIBLE');\n        await generateAnswer(question, record);\n        kintone.showNotification('SUCCESS', '回答を生成しました。内容を確認して保存してください。');\n      } catch (error) {\n        kintone.showNotification('ERROR', '回答の生成中にエラーが発生しました。');\n        console.error(error);\n      } finally {\n        kintone.showLoading('HIDDEN');\n      }\n    };\n    spaceElement.appendChild(answerButton);\n\n    return event;\n  });\n\n  async function generateAnswer(question, record) {\n    // AIへのリクエスト処理\n    const [body] = await kintone.proxy(\n      'https://ai.example.com/generate',\n      'POST',\n      { 'Content-Type': 'application/json' },\n      JSON.stringify({ question: question })\n    );\n    const { answer } = JSON.parse(body); // AIから取得した回答を入れる\n    record.record['回答欄'].value = answer;\n    kintone.app.record.set(record);\n  }\n})();\n```\n\n確認ダイアログで実行可否を確認し、進捗中はローディングを表示し、最後に結果を通知バナーに表示することで、ユーザーにとって分かりやすい操作フローを作れます。\n\n## まとめ\n\n本記事では、確認ダイアログと通知バナーAPIを使った「確認→進捗→結果」の3ステップ設計を紹介しました。\n\n最後に、用途ごとの使い分けをフローで整理します。\n\n```plantuml\n@startuml\nstart\n\npartition \"① 確認 - ダイアログ\" {\n  if (ダイアログに入力フォームが必要?) then (yes)\n    #D6EAF8:kintone.createDialog()\\nkintone.mobile.createBottomSheet();\n  else (no - テキストのみ)\n    #D6EAF8:kintone.showConfirmDialog()\\nkintone.mobile.showConfirmBottomSheet();\n    note right: 「OK/キャンセル」で\\n確認するだけならこちら\n  endif\n\n  if (OKを選択?) then (yes)\n  else (キャンセル)\n    stop\n  endif\n}\n\npartition \"② 進捗 - ローディング\" {\n  #FEF9E7:kintone.showLoading('VISIBLE');\n  :処理実行（JS API / REST API）;\n  #FEF9E7:kintone.showLoading('HIDDEN');\n}\n\npartition \"③ 結果 - 通知バナー\" {\n  if (処理が成功?) then (yes)\n    #D5F5E3:kintone.showNotification('SUCCESS', ...);\n  else (no)\n    #FADBD8:kintone.showNotification('ERROR', ...);\n  endif\n}\n\nstop\n@enduml\n```\n\nダイアログAPIの使い分けについては、次の記事も参考にしてください。\n\nhttps://cybozu.dev/ja/kintone/tips/development/customize/development-know-how/dialog-api-comparison/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article\n\n## おわりに\n\n確認ダイアログや通知バナーAPIを組み合わせるだけでも、カスタマイズの使い勝手は大きく変わります。\n\nまとめのフロー図を参考に「ユーザー対話型カスタマイズ」を意識して、  \nご自身のkintoneカスタマイズにも活用してみてください。\n\n:::note warn\nこの記事は、2026年4月版kintoneで動作を確認しています。\n:::\n\n## 参考リンク\n\n- [確認ダイアログを表示する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-dialog/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n- [ダイアログを作成する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-dialog/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n- [画面上部にメッセージを表示する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-notification/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n- [ローディングを表示する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-loading/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n- [確認ボトムシートを表示する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/show-confirm-bottomsheet/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n- [ボトムシートを作成する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/create-bottomsheet/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n- [モバイル版の画面かどうかを取得する - cybozu developer network](https://cybozu.dev/ja/kintone/docs/js-api/kintone/is-mobile-page/?utm_source=qiita\u0026utm_medium=referral\u0026utm_campaign=org_article)\n","coediting":false,"comments_count":0,"created_at":"2026-04-27T11:29:56+09:00","group":null,"id":"022e63a673349826aa38","likes_count":9,"private":false,"reactions_count":0,"stocks_count":1,"tags":[{"name":"JavaScript","versions":[]},{"name":"kintone","versions":[]},{"name":"kintoneカスタマイズ","versions":[]}],"title":"kintoneで確認ダイアログと通知バナーを使って誤操作を防ぐUXを実装してみよう","updated_at":"2026-04-27T11:29:56+09:00","url":"https://qiita.com/mu2in/items/022e63a673349826aa38","user":{"description":"広島で働いているふつうのプログラマ。\r\n※投稿内容は個人の見解であり、所属組織の公式見解ではありません。","facebook_id":"","followees_count":0,"followers_count":3,"github_login_name":"mu2in","id":"mu2in","items_count":1,"linkedin_id":"","location":"","name":"","organization":"サイボウズ株式会社","permanent_id":68679,"profile_image_url":"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68679/profile-images/1708951171","team_only":false,"twitter_screen_name":null,"website_url":""},"page_views_count":null,"team_membership":null,"organization_url_name":"kintone","slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:131\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/a2f26c8931c4802ad1b7\" id=\"reference-0f3cd0af764d450e8bd7\"\u003ekintone でSQL実行しよう その１０（cli対応）\u003c/a\u003eの続きです。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"3:1-3:8\"\u003e\n\u003cspan id=\"概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e概要\u003c/h1\u003e\n\u003cp data-sourcepos=\"5:1-9:123\"\u003eJOIN 時のレコード取得条件が気になったので改善してみます。\u003cbr\u003e\nどちらもレコード数が多い場合に、パフォーマンスに影響します。\u003cbr\u003e\n今回は、Claude Code で対応しました。\u003cbr\u003e\n手順書を作って、実装するとわかりやすい気がする。\u003cbr\u003e\n週間制限がリセットされると使わないともったいない気がするのは、ただの貧乏性ですね。\u003c/p\u003e\n\u003cp data-sourcepos=\"11:1-11:88\"\u003e\u003ca href=\"https://github.com/rex0220/kintone-sql-tools\" rel=\"nofollow noopener\" target=\"_blank\"\u003ekintone-sql-tools\u003c/a\u003e V1.1.2 で公開済み\u003c/p\u003e\n\u003cul data-sourcepos=\"13:1-14:0\"\u003e\n\u003cli data-sourcepos=\"13:1-14:0\"\u003eWHERE 条件 Push Down（JOIN 時のレコード取得最適化）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"15:1-15:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F95928e41-5aa2-4bb5-a7db-b232522c4fc8.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=80a876405b49af861309a4ff1b465e5c\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F95928e41-5aa2-4bb5-a7db-b232522c4fc8.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=80a876405b49af861309a4ff1b465e5c\" alt=\"2026-04-26_12h21_34.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F95928e41-5aa2-4bb5-a7db-b232522c4fc8.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=e4e3a663127141aab2c9686b8821f8eb 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/95928e41-5aa2-4bb5-a7db-b232522c4fc8.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"17:1-18:0\"\u003e\n\u003cli data-sourcepos=\"17:1-18:0\"\u003eON 条件で、REST API 呼び出し増大\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"19:1-19:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F33c997e1-2ff7-42f7-b96c-cc2feb0116b0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=82775220d254e794f623ddde9f644c50\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F33c997e1-2ff7-42f7-b96c-cc2feb0116b0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=82775220d254e794f623ddde9f644c50\" alt=\"2026-04-26_12h19_30.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F33c997e1-2ff7-42f7-b96c-cc2feb0116b0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=295c53c59d9ef85a8385f2b90979f3f9 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/33c997e1-2ff7-42f7-b96c-cc2feb0116b0.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"22:1-22:68\"\u003e\n\u003cspan id=\"where-条件-push-downjoin-時のレコード取得最適化\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#where-%E6%9D%A1%E4%BB%B6-push-downjoin-%E6%99%82%E3%81%AE%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E5%8F%96%E5%BE%97%E6%9C%80%E9%81%A9%E5%8C%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eWHERE 条件 Push Down（JOIN 時のレコード取得最適化）\u003c/h1\u003e\n\u003ch2 data-sourcepos=\"24:1-24:9\"\u003e\n\u003cspan id=\"背景\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%83%8C%E6%99%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e背景\u003c/h2\u003e\n\u003cp data-sourcepos=\"26:1-27:60\"\u003eJOIN クエリは現状 \u003ccode\u003eFULL_SCAN\u003c/code\u003e モードで実行され、各テーブルのレコードを全件取得したあと\u003cbr\u003e\nJavaScript 側で WHERE フィルタを適用している。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"29:1-37:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e会社名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n       \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e商談フェーズ\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e売上\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4148\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\n\u003cspan class=\"k\"\u003eINNER\u003c/span\u003e \u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4149\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"k\"\u003eON\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e商談フェーズ\u003c/span\u003e \u003cspan class=\"k\"\u003eIN\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e'提案中'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e'内示'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e'受注'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n  \u003cspan class=\"k\"\u003eAND\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e \u003cspan class=\"k\"\u003eIN\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e'A'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"39:1-39:27\"\u003e現在の EXPLAIN 出力：\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"41:1-50:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003emode: FULL_SCAN\nreason: JOIN あり\napp: APP4148 AS a (4148)\nkintone query: (全件取得)\nfields: 顧客No, 会社名, 顧客ランク\nJOIN: APP4149 AS b (4149)\nkintone query: (全件取得)\nfields: 案件No_, 案件名, 商談フェーズ, 売上, 顧客No_\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"52:1-52:9\"\u003e\n\u003cspan id=\"目標\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%9B%AE%E6%A8%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e目標\u003c/h2\u003e\n\u003cp data-sourcepos=\"54:1-55:91\"\u003eWHERE 条件を各テーブルへ分解（Predicate Pushdown）し、\u003cbr\u003e\nkintone API の query パラメータに乗せて必要なレコードのみ取得する。\u003c/p\u003e\n\u003cp data-sourcepos=\"57:1-57:27\"\u003e目標の EXPLAIN 出力：\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"59:1-68:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003emode: FULL_SCAN\nreason: JOIN あり\napp: APP4148 AS a (4148)\nkintone query: 顧客ランク in (\"A\")\nfields: 顧客No, 会社名, 顧客ランク\nJOIN: APP4149 AS b (4149)\nkintone query: 商談フェーズ in (\"提案中\",\"内示\",\"受注\")\nfields: 案件No_, 案件名, 商談フェーズ, 売上, 顧客No_\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"70:1-70:34\"\u003e\n\u003cspan id=\"push-down-可否の判定基準\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#push-down-%E5%8F%AF%E5%90%A6%E3%81%AE%E5%88%A4%E5%AE%9A%E5%9F%BA%E6%BA%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ePush Down 可否の判定基準\u003c/h2\u003e\n\u003ctable data-sourcepos=\"72:1-83:87\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"72:1-72:37\"\u003e\n\u003cth data-sourcepos=\"72:2-72:18\"\u003e条件の種類\u003c/th\u003e\n\u003cth data-sourcepos=\"72:20-72:27\"\u003e判定\u003c/th\u003e\n\u003cth data-sourcepos=\"72:29-72:36\"\u003e理由\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"74:1-74:97\"\u003e\n\u003ctd data-sourcepos=\"74:2-74:53\"\u003e\n\u003ccode\u003ea.field = value\u003c/code\u003e / \u003ccode\u003e!=\u003c/code\u003e / \u003ccode\u003e\u0026gt;\u003c/code\u003e / \u003ccode\u003e\u0026lt;\u003c/code\u003e / \u003ccode\u003e\u0026gt;=\u003c/code\u003e / \u003ccode\u003e\u0026lt;=\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-sourcepos=\"74:55-74:63\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"74:65-74:96\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"75:1-75:67\"\u003e\n\u003ctd data-sourcepos=\"75:2-75:23\"\u003e\u003ccode\u003ea.field LIKE value\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"75:25-75:33\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"75:35-75:66\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"76:1-76:71\"\u003e\n\u003ctd data-sourcepos=\"76:2-76:27\"\u003e\u003ccode\u003ea.field NOT LIKE value\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"76:29-76:37\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"76:39-76:70\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"77:1-77:65\"\u003e\n\u003ctd data-sourcepos=\"77:2-77:21\"\u003e\u003ccode\u003ea.field IN (...)\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"77:23-77:31\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"77:33-77:64\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"78:1-78:69\"\u003e\n\u003ctd data-sourcepos=\"78:2-78:25\"\u003e\u003ccode\u003ea.field NOT IN (...)\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"78:27-78:35\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"78:37-78:68\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"79:1-79:78\"\u003e\n\u003ctd data-sourcepos=\"79:2-79:34\"\u003e\u003ccode\u003ea.field IS NULL / IS NOT NULL\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"79:36-79:44\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"79:46-79:77\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"80:1-80:91\"\u003e\n\u003ctd data-sourcepos=\"80:2-80:39\"\u003e\n\u003ccode\u003eAND\u003c/code\u003e の両辺が同一テーブル\u003c/td\u003e\n\u003ctd data-sourcepos=\"80:41-80:49\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"80:51-80:90\"\u003e分割して各 API に適用できる\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"81:1-81:91\"\u003e\n\u003ctd data-sourcepos=\"81:2-81:41\"\u003e\n\u003ccode\u003eOR\u003c/code\u003e の両辺が異なるテーブル\u003c/td\u003e\n\u003ctd data-sourcepos=\"81:43-81:54\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"81:56-81:90\"\u003e分離すると結果が変わる\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"82:1-82:104\"\u003e\n\u003ctd data-sourcepos=\"82:2-82:49\"\u003e\n\u003ccode\u003ea.field = b.field\u003c/code\u003e（クロステーブル）\u003c/td\u003e\n\u003ctd data-sourcepos=\"82:51-82:62\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"82:64-82:103\"\u003eJOIN 後でないと評価できない\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"83:1-83:87\"\u003e\n\u003ctd data-sourcepos=\"83:2-83:49\"\u003e\n\u003ccode\u003eUPPER(a.field) = value\u003c/code\u003e 等（関数付き）\u003c/td\u003e\n\u003ctd data-sourcepos=\"83:51-83:62\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"83:64-83:86\"\u003ekintone API 非対応\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cblockquote data-sourcepos=\"85:1-85:75\"\u003e\n\u003cp data-sourcepos=\"85:3-85:75\"\u003e\u003cstrong\u003e原則\u003c/strong\u003e：\u003ccode\u003ewhereToKintone\u003c/code\u003e が変換できる演算子 = push down 可\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 data-sourcepos=\"87:1-87:21\"\u003e\n\u003cspan id=\"実装ステップ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E3%82%B9%E3%83%86%E3%83%83%E3%83%97\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装ステップ\u003c/h2\u003e\n\u003chr data-sourcepos=\"89:1-90:0\"\u003e\n\u003ch3 data-sourcepos=\"91:1-91:43\"\u003e\n\u003cspan id=\"step-1条件分離ロジック作成\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-1%E6%9D%A1%E4%BB%B6%E5%88%86%E9%9B%A2%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E4%BD%9C%E6%88%90\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 1：条件分離ロジック作成\u003c/h3\u003e\n\u003cp data-sourcepos=\"93:1-93:74\"\u003e\u003cstrong\u003e新規ファイル\u003c/strong\u003e：\u003ccode\u003esrc/core/optimization/wherePredicatePushdown.ts\u003c/code\u003e\u003c/p\u003e\n\u003ch4 data-sourcepos=\"95:1-95:23\"\u003e\n\u003cspan id=\"実装する関数\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装する関数\u003c/h4\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"97:1-106:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"cm\"\u003e/**\n * WHERE 式からテーブルエイリアスに対応する push down 可能な条件を抽出する。\n * 抽出できない（クロステーブル・OR・関数付き）条件は null を返す。\n */\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e \u003cspan class=\"nf\"\u003eextractTableCondition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n  \u003cspan class=\"nx\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eWhereExpr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"nx\"\u003etableAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e\n\u003cspan class=\"p\"\u003e):\u003c/span\u003e \u003cspan class=\"nx\"\u003eWhereExpr\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch4 data-sourcepos=\"108:1-108:23\"\u003e\n\u003cspan id=\"アルゴリズム\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eアルゴリズム\u003c/h4\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"110:1-128:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eextractTableCondition(expr, alias):\n  BINARY / NULL_CHECK:\n    → 参照フィールドが alias のみ かつ 関数なし → そのまま返す\n    → それ以外 → null\n\n  LOGICAL AND:\n    left  = extractTableCondition(left,  alias)\n    right = extractTableCondition(right, alias)\n    → both non-null : AND(left, right) を返す\n    → one non-null  : non-null 側を返す\n    → both null     : null を返す\n\n  LOGICAL OR:\n    → 両辺が異なるテーブルを参照する可能性 → null を返す（安全側）\n\n  NOT / GROUP:\n    → null を返す（複雑化を避け JavaScript 側に委ねる）\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch4 data-sourcepos=\"130:1-130:29\"\u003e\n\u003cspan id=\"呼び出しイメージ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e呼び出しイメージ\u003c/h4\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"132:1-139:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// WHERE 全体から各テーブル用の条件を取り出す\u003c/span\u003e\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003econdA\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eextractTableCondition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"dl\"\u003e\"\u003c/span\u003e\u003cspan class=\"s2\"\u003ea\u003c/span\u003e\u003cspan class=\"dl\"\u003e\"\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// → BinaryExpr { op: \"IN\", left: a.顧客ランク, right: [\"A\"] }\u003c/span\u003e\n\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003econdB\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eextractTableCondition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"dl\"\u003e\"\u003c/span\u003e\u003cspan class=\"s2\"\u003eb\u003c/span\u003e\u003cspan class=\"dl\"\u003e\"\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// → BinaryExpr { op: \"IN\", left: b.商談フェーズ, right: [\"提案中\",\"内示\",\"受注\"] }\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch4 data-sourcepos=\"141:1-141:20\"\u003e\n\u003cspan id=\"テスト項目\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%86%E3%82%B9%E3%83%88%E9%A0%85%E7%9B%AE\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eテスト項目\u003c/h4\u003e\n\u003cul data-sourcepos=\"143:1-148:0\"\u003e\n\u003cli data-sourcepos=\"143:1-143:83\"\u003e\n\u003ccode\u003eAND\u003c/code\u003e でつながれた異なるテーブルの条件が正しく分離される\u003c/li\u003e\n\u003cli data-sourcepos=\"144:1-144:57\"\u003e\n\u003ccode\u003eOR\u003c/code\u003e でつながれた条件は push down されない\u003c/li\u003e\n\u003cli data-sourcepos=\"145:1-145:80\"\u003eクロステーブル条件（\u003ccode\u003ea.field = b.field\u003c/code\u003e）は push down されない\u003c/li\u003e\n\u003cli data-sourcepos=\"146:1-146:68\"\u003e関数付き条件（\u003ccode\u003eUPPER(a.field)\u003c/code\u003e）は push down されない\u003c/li\u003e\n\u003cli data-sourcepos=\"147:1-148:0\"\u003eエイリアスなし条件（\u003ccode\u003efield = value\u003c/code\u003e、JOIN なし相当）の扱い\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr data-sourcepos=\"149:1-150:0\"\u003e\n\u003ch3 data-sourcepos=\"151:1-151:69\"\u003e\n\u003cspan id=\"step-2wheretokintone-のエイリアス対応確認修正\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-2wheretokintone-%E3%81%AE%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9%E5%AF%BE%E5%BF%9C%E7%A2%BA%E8%AA%8D%E4%BF%AE%E6%AD%A3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 2：\u003ccode\u003ewhereToKintone\u003c/code\u003e のエイリアス対応確認・修正\u003c/h3\u003e\n\u003cp data-sourcepos=\"153:1-153:52\"\u003e\u003cstrong\u003eファイル\u003c/strong\u003e：\u003ccode\u003esrc/converter/whereToKintone.ts\u003c/code\u003e\u003c/p\u003e\n\u003ch4 data-sourcepos=\"155:1-155:17\"\u003e\n\u003cspan id=\"確認内容\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%A2%BA%E8%AA%8D%E5%86%85%E5%AE%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e確認内容\u003c/h4\u003e\n\u003cp data-sourcepos=\"157:1-158:112\"\u003e\u003ccode\u003ea.顧客ランク IN ('A')\u003c/code\u003e のように \u003ccode\u003eFieldRef.tableAlias\u003c/code\u003e が付いた条件を\u003cbr\u003e\n\u003ccode\u003ewhereToKintone\u003c/code\u003e に渡したとき、kintone query 文字列として正しく出力されるか確認する。\u003c/p\u003e\n\u003cp data-sourcepos=\"160:1-160:21\"\u003e期待する変換：\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"162:1-164:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003ea.顧客ランク in (\"A\")  →  顧客ランク in (\"A\")   ← エイリアスを除去\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch4 data-sourcepos=\"166:1-166:17\"\u003e\n\u003cspan id=\"修正方針\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BF%AE%E6%AD%A3%E6%96%B9%E9%87%9D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e修正方針\u003c/h4\u003e\n\u003cp data-sourcepos=\"168:1-168:161\"\u003e\u003ccode\u003eFieldRef\u003c/code\u003e 処理箇所でエイリアスを除いたフィールド名のみを使用するよう修正する（既に対応済みの場合はスキップ）。\u003c/p\u003e\n\u003chr data-sourcepos=\"170:1-171:0\"\u003e\n\u003ch3 data-sourcepos=\"172:1-172:55\"\u003e\n\u003cspan id=\"step-3executets-に-push-down-を組み込む\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-3executets-%E3%81%AB-push-down-%E3%82%92%E7%B5%84%E3%81%BF%E8%BE%BC%E3%82%80\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 3：\u003ccode\u003eexecute.ts\u003c/code\u003e に push down を組み込む\u003c/h3\u003e\n\u003cp data-sourcepos=\"174:1-174:35\"\u003e\u003cstrong\u003eファイル\u003c/strong\u003e：\u003ccode\u003esrc/execute.ts\u003c/code\u003e\u003c/p\u003e\n\u003ch4 data-sourcepos=\"176:1-176:76\"\u003e\n\u003cspan id=\"変更箇所-1executefullscanselectpush-down-条件の計算\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%A4%89%E6%9B%B4%E7%AE%87%E6%89%80-1executefullscanselectpush-down-%E6%9D%A1%E4%BB%B6%E3%81%AE%E8%A8%88%E7%AE%97\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e変更箇所 1：\u003ccode\u003eexecuteFullScanSelect\u003c/code\u003e（push down 条件の計算）\u003c/h4\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"178:1-193:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// executeFullScanSelect の冒頭で各テーブルの push down 条件を計算\u003c/span\u003e\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003etableConditions\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nb\"\u003eMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eWhereExpr\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewhere\u003c/span\u003e \u003cspan class=\"o\"\u003e!==\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003emainAlias\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ealias\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"nc\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eappId\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n  \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003econd\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eextractTableCondition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003emainAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n  \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econd\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nx\"\u003etableConditions\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003emainAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003econd\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n  \u003cspan class=\"k\"\u003efor \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ejoin\u003c/span\u003e \u003cspan class=\"k\"\u003eof\u003c/span\u003e \u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ejoins\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ejoinAlias\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etable\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ealias\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"nc\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etable\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eappId\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003econd\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eextractTableCondition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ejoinAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n    \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econd\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nx\"\u003etableConditions\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ejoinAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003econd\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch4 data-sourcepos=\"195:1-195:87\"\u003e\n\u003cspan id=\"変更箇所-2fetchtablerecordsforfullscanmain-テーブルへの適用\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%A4%89%E6%9B%B4%E7%AE%87%E6%89%80-2fetchtablerecordsforfullscanmain-%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%B8%E3%81%AE%E9%81%A9%E7%94%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e変更箇所 2：\u003ccode\u003efetchTableRecordsForFullScan\u003c/code\u003e（main テーブルへの適用）\u003c/h4\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"197:1-202:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 現状: JOIN ありの場合 WHERE を API に渡さない\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 変更後: push down 条件が存在すれば kintone query に追加\u003c/span\u003e\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003epushDownCond\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003etableConditions\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003emainAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003equery\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003ebuildFetchQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003etable\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eappId\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003epushDownCond\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch4 data-sourcepos=\"204:1-204:90\"\u003e\n\u003cspan id=\"変更箇所-3tryfetchjoinrecordsbysourcekeysjoin-テーブルへの適用\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%A4%89%E6%9B%B4%E7%AE%87%E6%89%80-3tryfetchjoinrecordsbysourcekeysjoin-%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%B8%E3%81%AE%E9%81%A9%E7%94%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e変更箇所 3：\u003ccode\u003etryFetchJoinRecordsBySourceKeys\u003c/code\u003e（JOIN テーブルへの適用）\u003c/h4\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"206:1-214:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 既存: \"joinField in (v1, v2, ...)\" を生成\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 変更後: push down 条件がある場合は AND で結合\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// \"joinField in (v1, v2, ...) and 商談フェーズ in (\"提案中\",\"内示\",\"受注\")\"\u003c/span\u003e\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003epushDownCond\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003etableConditions\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ejoinAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ecombinedQuery\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003epushDownCond\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e?\u003c/span\u003e \u003cspan class=\"s2\"\u003e`\u003c/span\u003e\u003cspan class=\"p\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003einClause\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e and \u003c/span\u003e\u003cspan class=\"p\"\u003e${\u003c/span\u003e\u003cspan class=\"nf\"\u003ewhereToKintone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epushDownCond\u003c/span\u003e\u003cspan class=\"p\"\u003e)}\u003c/span\u003e\u003cspan class=\"s2\"\u003e`\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003einClause\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cblockquote data-sourcepos=\"216:1-217:117\"\u003e\n\u003cp data-sourcepos=\"216:3-217:117\"\u003eJavaScript 側の \u003ccode\u003eapplyFilter\u003c/code\u003e（全件 WHERE 評価）は \u003cstrong\u003eそのまま維持\u003c/strong\u003eする。\u003cbr\u003e\npush down は絞り込みの最適化であり、結果の正確性は JavaScript 側フィルタが保証する。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr data-sourcepos=\"219:1-220:0\"\u003e\n\u003ch3 data-sourcepos=\"221:1-221:36\"\u003e\n\u003cspan id=\"step-4explain-表示の更新\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-4explain-%E8%A1%A8%E7%A4%BA%E3%81%AE%E6%9B%B4%E6%96%B0\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 4：EXPLAIN 表示の更新\u003c/h3\u003e\n\u003cp data-sourcepos=\"223:1-223:59\"\u003e\u003cstrong\u003eファイル\u003c/strong\u003e：\u003ccode\u003esrc/core/optimization/sharedPlanner.js\u003c/code\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"225:1-225:70\"\u003epush down 後の実際の kintone query を EXPLAIN に反映する。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"227:1-230:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e変更前: kintone query: (全件取得)\n変更後: kintone query: 顧客ランク in (\"A\")\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"232:1-232:82\"\u003epush down 条件がない場合は引き続き \u003ccode\u003e(全件取得)\u003c/code\u003e と表示する。\u003c/p\u003e\n\u003chr data-sourcepos=\"234:1-235:0\"\u003e\n\u003ch3 data-sourcepos=\"236:1-236:43\"\u003e\n\u003cspan id=\"step-5統合テスト動作確認\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-5%E7%B5%B1%E5%90%88%E3%83%86%E3%82%B9%E3%83%88%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 5：統合テスト・動作確認\u003c/h3\u003e\n\u003ch4 data-sourcepos=\"238:1-238:38\"\u003e\n\u003cspan id=\"確認するクエリパターン\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e確認するクエリパターン\u003c/h4\u003e\n\u003ctable data-sourcepos=\"240:1-246:92\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"240:1-240:43\"\u003e\n\u003cth data-sourcepos=\"240:2-240:15\"\u003eパターン\u003c/th\u003e\n\u003cth data-sourcepos=\"240:17-240:27\"\u003epush down\u003c/th\u003e\n\u003cth data-sourcepos=\"240:29-240:42\"\u003e期待動作\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"242:1-242:108\"\u003e\n\u003ctd data-sourcepos=\"242:2-242:49\"\u003eAND で各テーブル条件が分離できる\u003c/td\u003e\n\u003ctd data-sourcepos=\"242:51-242:74\"\u003e✅ 両テーブルへ\u003c/td\u003e\n\u003ctd data-sourcepos=\"242:76-242:107\"\u003eレコード取得数が減少\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"243:1-243:89\"\u003e\n\u003ctd data-sourcepos=\"243:2-243:30\"\u003eOR でつながれた条件\u003c/td\u003e\n\u003ctd data-sourcepos=\"243:32-243:43\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"243:45-243:88\"\u003e全件取得のまま（正確性維持）\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"244:1-244:74\"\u003e\n\u003ctd data-sourcepos=\"244:2-244:36\"\u003eクロステーブル条件のみ\u003c/td\u003e\n\u003ctd data-sourcepos=\"244:38-244:49\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"244:51-244:73\"\u003e全件取得のまま\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"245:1-245:37\"\u003e\n\u003ctd data-sourcepos=\"245:2-245:15\"\u003eWHERE なし\u003c/td\u003e\n\u003ctd data-sourcepos=\"245:17-245:21\"\u003e—\u003c/td\u003e\n\u003ctd data-sourcepos=\"245:23-245:36\"\u003e変化なし\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"246:1-246:92\"\u003e\n\u003ctd data-sourcepos=\"246:2-246:38\"\u003emain テーブルのみ条件あり\u003c/td\u003e\n\u003ctd data-sourcepos=\"246:40-246:56\"\u003e✅ main のみ\u003c/td\u003e\n\u003ctd data-sourcepos=\"246:58-246:91\"\u003eJOIN テーブルは全件取得\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 data-sourcepos=\"248:1-248:29\"\u003e\n\u003cspan id=\"結果の正確性確認\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%B5%90%E6%9E%9C%E3%81%AE%E6%AD%A3%E7%A2%BA%E6%80%A7%E7%A2%BA%E8%AA%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e結果の正確性確認\u003c/h4\u003e\n\u003cp data-sourcepos=\"250:1-250:95\"\u003epush down あり / なし で同一クエリの結果行が一致することを確認する。\u003c/p\u003e\n\u003chr data-sourcepos=\"252:1-253:0\"\u003e\n\u003ch2 data-sourcepos=\"254:1-254:27\"\u003e\n\u003cspan id=\"修正ファイル一覧\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BF%AE%E6%AD%A3%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E4%B8%80%E8%A6%A7\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e修正ファイル一覧\u003c/h2\u003e\n\u003ctable data-sourcepos=\"256:1-261:76\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"256:1-256:34\"\u003e\n\u003cth data-sourcepos=\"256:2-256:15\"\u003eファイル\u003c/th\u003e\n\u003cth data-sourcepos=\"256:17-256:24\"\u003e種別\u003c/th\u003e\n\u003cth data-sourcepos=\"256:26-256:33\"\u003e内容\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"258:1-258:89\"\u003e\n\u003ctd data-sourcepos=\"258:2-258:52\"\u003e\u003ccode\u003esrc/core/optimization/wherePredicatePushdown.ts\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"258:54-258:61\"\u003e新規\u003c/td\u003e\n\u003ctd data-sourcepos=\"258:63-258:88\"\u003e条件分離ロジック\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"259:1-259:91\"\u003e\n\u003ctd data-sourcepos=\"259:2-259:36\"\u003e\u003ccode\u003esrc/converter/whereToKintone.ts\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"259:38-259:60\"\u003e修正（要確認）\u003c/td\u003e\n\u003ctd data-sourcepos=\"259:62-259:90\"\u003eエイリアス除去対応\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"260:1-260:66\"\u003e\n\u003ctd data-sourcepos=\"260:2-260:19\"\u003e\u003ccode\u003esrc/execute.ts\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"260:21-260:28\"\u003e修正\u003c/td\u003e\n\u003ctd data-sourcepos=\"260:30-260:65\"\u003epush down 条件の計算・適用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"261:1-261:76\"\u003e\n\u003ctd data-sourcepos=\"261:2-261:43\"\u003e\u003ccode\u003esrc/core/optimization/sharedPlanner.js\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"261:45-261:52\"\u003e修正\u003c/td\u003e\n\u003ctd data-sourcepos=\"261:54-261:75\"\u003eEXPLAIN 表示更新\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 data-sourcepos=\"263:1-263:33\"\u003e\n\u003cspan id=\"ブランチマージ手順\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E3%83%9E%E3%83%BC%E3%82%B8%E6%89%8B%E9%A0%86\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eブランチ・マージ手順\u003c/h2\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"265:1-285:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c\"\u003e# 作業ブランチ（作成済み）\u003c/span\u003e\ngit checkout perf/where-pushdown-join\n\n\u003cspan class=\"c\"\u003e# 各ステップをコミット\u003c/span\u003e\ngit add src/core/optimization/wherePredicatePushdown.ts\ngit commit \u003cspan class=\"nt\"\u003e-m\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"perf: add WHERE predicate pushdown extraction logic\"\u003c/span\u003e\n\ngit add src/converter/whereToKintone.ts\ngit commit \u003cspan class=\"nt\"\u003e-m\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"perf: strip table alias in whereToKintone for pushdown\"\u003c/span\u003e\n\ngit add src/execute.ts\ngit commit \u003cspan class=\"nt\"\u003e-m\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"perf: apply per-table WHERE conditions to kintone API calls\"\u003c/span\u003e\n\ngit add src/core/optimization/sharedPlanner.js\ngit commit \u003cspan class=\"nt\"\u003e-m\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"perf: show pushed-down kintone query in EXPLAIN output\"\u003c/span\u003e\n\n\u003cspan class=\"c\"\u003e# PR 作成\u003c/span\u003e\ngit push \u003cspan class=\"nt\"\u003e-u\u003c/span\u003e origin perf/where-pushdown-join\ngh \u003cspan class=\"nb\"\u003epr \u003c/span\u003ecreate \u003cspan class=\"nt\"\u003e--title\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"perf: WHERE predicate pushdown for JOIN queries\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch1 data-sourcepos=\"288:1-288:66\"\u003e\n\u003cspan id=\"on-条件による-rest-api-呼び出し増大原因と対策\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#on-%E6%9D%A1%E4%BB%B6%E3%81%AB%E3%82%88%E3%82%8B-rest-api-%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E5%A2%97%E5%A4%A7%E5%8E%9F%E5%9B%A0%E3%81%A8%E5%AF%BE%E7%AD%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eON 条件による REST API 呼び出し増大：原因と対策\u003c/h1\u003e\n\u003ch2 data-sourcepos=\"290:1-290:9\"\u003e\n\u003cspan id=\"背景-1\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%83%8C%E6%99%AF-1\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e背景\u003c/h2\u003e\n\u003cp data-sourcepos=\"292:1-293:121\"\u003eJOIN クエリは kintone API が直接サポートしないため、FULL_SCAN モードで実行される。\u003cbr\u003e\n各テーブルを個別に API から取得し、JavaScript 側で結合・フィルタする構成になっている。\u003c/p\u003e\n\u003chr data-sourcepos=\"295:1-296:0\"\u003e\n\u003ch2 data-sourcepos=\"297:1-297:45\"\u003e\n\u003cspan id=\"原因on-最適化のチャンク分割\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%8E%9F%E5%9B%A0on-%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%AE%E3%83%81%E3%83%A3%E3%83%B3%E3%82%AF%E5%88%86%E5%89%B2\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e原因：ON 最適化のチャンク分割\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"299:1-299:22\"\u003e\n\u003cspan id=\"on-最適化とは\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#on-%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%A8%E3%81%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eON 最適化とは\u003c/h3\u003e\n\u003cp data-sourcepos=\"301:1-301:128\"\u003eJOIN 先テーブルの全件取得を避けるため、結合キーの値セットを IN 句として API に渡す最適化。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"303:1-309:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e会社名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件名\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4148\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\n\u003cspan class=\"k\"\u003eINNER\u003c/span\u003e \u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4149\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"k\"\u003eON\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e商談フェーズ\u003c/span\u003e \u003cspan class=\"k\"\u003eIN\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e'提案中'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e'内示'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e'受注'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n  \u003cspan class=\"k\"\u003eAND\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e \u003cspan class=\"k\"\u003eIN\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e'A'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"311:1-316:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e① APP4148 を全件取得（顧客ランク フィルタあり）\n② ①の結果から 顧客No_ のユニーク値を収集\n③ APP4149 に IN 句で絞り込みリクエスト\n   → 顧客No_ in (\"v1\",\"v2\",...,\"v50\")   ← 50件ずつチャンク\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"318:1-318:22\"\u003e\n\u003cspan id=\"チャンク上限\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%81%E3%83%A3%E3%83%B3%E3%82%AF%E4%B8%8A%E9%99%90\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eチャンク上限\u003c/h3\u003e\n\u003ctable data-sourcepos=\"320:1-324:61\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"320:1-320:25\"\u003e\n\u003cth data-sourcepos=\"320:2-320:9\"\u003e定数\u003c/th\u003e\n\u003cth data-sourcepos=\"320:11-320:15\"\u003e値\u003c/th\u003e\n\u003cth data-sourcepos=\"320:17-320:24\"\u003e意味\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"322:1-322:70\"\u003e\n\u003ctd data-sourcepos=\"322:2-322:23\"\u003e\u003ccode\u003eJOIN_IN_CHUNK_SIZE\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"322:25-322:28\"\u003e50\u003c/td\u003e\n\u003ctd data-sourcepos=\"322:30-322:69\"\u003e1リクエストあたりの IN 値数\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"323:1-323:52\"\u003e\n\u003ctd data-sourcepos=\"323:2-323:23\"\u003e\u003ccode\u003eJOIN_IN_MAX_CHUNKS\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"323:25-323:27\"\u003e6\u003c/td\u003e\n\u003ctd data-sourcepos=\"323:29-323:51\"\u003e最大チャンク数\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"324:1-324:61\"\u003e\n\u003ctd data-sourcepos=\"324:2-324:21\"\u003e\u003ccode\u003eJOIN_IN_MAX_KEYS\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"324:23-324:27\"\u003e300\u003c/td\u003e\n\u003ctd data-sourcepos=\"324:29-324:60\"\u003eON 最適化の上限キー数\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 data-sourcepos=\"326:1-326:66\"\u003e\n\u003cspan id=\"問題キー数に比例して-api-呼び出しが増える\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%95%8F%E9%A1%8C%E3%82%AD%E3%83%BC%E6%95%B0%E3%81%AB%E6%AF%94%E4%BE%8B%E3%81%97%E3%81%A6-api-%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%81%8C%E5%A2%97%E3%81%88%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e問題：キー数に比例して API 呼び出しが増える\u003c/h3\u003e\n\u003ctable data-sourcepos=\"328:1-333:89\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"328:1-328:95\"\u003e\n\u003cth data-sourcepos=\"328:2-328:35\"\u003e顧客ランク='A' の顧客数\u003c/th\u003e\n\u003cth data-sourcepos=\"328:37-328:59\"\u003eON 最適化の挙動\u003c/th\u003e\n\u003cth data-sourcepos=\"328:61-328:94\"\u003eAPI 呼び出し数（APP4149）\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"330:1-330:35\"\u003e\n\u003ctd data-sourcepos=\"330:2-330:11\"\u003e〜50件\u003c/td\u003e\n\u003ctd data-sourcepos=\"330:13-330:27\"\u003e1チャンク\u003c/td\u003e\n\u003ctd data-sourcepos=\"330:29-330:34\"\u003e1回\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"331:1-331:38\"\u003e\n\u003ctd data-sourcepos=\"331:2-331:14\"\u003e51〜100件\u003c/td\u003e\n\u003ctd data-sourcepos=\"331:16-331:30\"\u003e2チャンク\u003c/td\u003e\n\u003ctd data-sourcepos=\"331:32-331:37\"\u003e2回\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"332:1-332:45\"\u003e\n\u003ctd data-sourcepos=\"332:2-332:15\"\u003e151〜300件\u003c/td\u003e\n\u003ctd data-sourcepos=\"332:17-332:37\"\u003e最大6チャンク\u003c/td\u003e\n\u003ctd data-sourcepos=\"332:39-332:44\"\u003e6回\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"333:1-333:89\"\u003e\n\u003ctd data-sourcepos=\"333:2-333:16\"\u003e\u003cstrong\u003e300件超\u003c/strong\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"333:18-333:62\"\u003e\u003cstrong\u003eフォールバック（全件取得）\u003c/strong\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"333:64-333:88\"\u003e\u003cstrong\u003e案件数 / 500 回\u003c/strong\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp data-sourcepos=\"335:1-336:54\"\u003e300件超でフォールバックが発生すると、APP4149 に10万件ある場合は\u003cbr\u003e\n\u003cstrong\u003e200回以上の API 呼び出し\u003c/strong\u003eが発生する。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"338:1-338:84\"\u003e\n\u003cspan id=\"実際の-api-リクエスト例300件超フォールバック時の警告\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E9%9A%9B%E3%81%AE-api-%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E4%BE%8B300%E4%BB%B6%E8%B6%85%E3%83%95%E3%82%A9%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF%E6%99%82%E3%81%AE%E8%AD%A6%E5%91%8A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実際の API リクエスト例（300件超フォールバック時の警告）\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"340:1-342:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eJOINキーが 312 件のため ON 最適化をスキップし、JOIN先を全件取得します（上限 300 件）。\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003chr data-sourcepos=\"344:1-345:0\"\u003e\n\u003ch2 data-sourcepos=\"346:1-346:9\"\u003e\n\u003cspan id=\"対策\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AF%BE%E7%AD%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e対策\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"348:1-348:102\"\u003e\n\u003cspan id=\"案1push-down-条件がある-join-テーブルは-on-最適化をスキップ--実装済み\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A1%881push-down-%E6%9D%A1%E4%BB%B6%E3%81%8C%E3%81%82%E3%82%8B-join-%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AF-on-%E6%9C%80%E9%81%A9%E5%8C%96%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97--%E5%AE%9F%E8%A3%85%E6%B8%88%E3%81%BF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e案1：push-down 条件がある JOIN テーブルは ON 最適化をスキップ ✅ 実装済み\u003c/h3\u003e\n\u003cp data-sourcepos=\"350:1-351:52\"\u003eJOIN テーブルに WHERE push-down 条件がある場合、ON 最適化（IN 句チャンク）を使わず\u003cbr\u003e\npush-down 条件のみで直接フェッチする。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"353:1-356:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eBefore: APP4148(filtered) → キー収集 → APP4149(IN×N回)\nAfter:  APP4149(push-down のみ) ← 1回のフェッチで完結\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"358:1-359:121\"\u003e\u003cstrong\u003e効果：\u003c/strong\u003e push-down 条件が絞り込める場合は API 呼び出しが大幅に減少\u003cbr\u003e\n\u003cstrong\u003e限界：\u003c/strong\u003e push-down 後の JOIN テーブルが大量レコードの場合は fetch 回数が増える可能性あり\u003c/p\u003e\n\u003chr data-sourcepos=\"361:1-362:0\"\u003e\n\u003ch3 data-sourcepos=\"363:1-363:98\"\u003e\n\u003cspan id=\"案2push-down-ありの-join-テーブルをメインと並列フェッチ--実装済み\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A1%882push-down-%E3%81%82%E3%82%8A%E3%81%AE-join-%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%A8%E4%B8%A6%E5%88%97%E3%83%95%E3%82%A7%E3%83%83%E3%83%81--%E5%AE%9F%E8%A3%85%E6%B8%88%E3%81%BF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e案2：push-down ありの JOIN テーブルをメインと並列フェッチ ✅ 実装済み\u003c/h3\u003e\n\u003cp data-sourcepos=\"365:1-365:127\"\u003epush-down 条件がある JOIN テーブルはメインテーブルの完了を待たず、同時にフェッチ開始する。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"367:1-370:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eBefore: APP4148 fetch → (完了待ち) → APP4149 fetch（直列）\nAfter:  APP4148 fetch ─並列─ APP4149 fetch（並列）\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"372:1-372:118\"\u003e\u003cstrong\u003e効果：\u003c/strong\u003e ウォール時間を短縮（API 回数は案1と同じ、レスポンス時間が半減に近づく）\u003c/p\u003e\n\u003chr data-sourcepos=\"374:1-375:0\"\u003e\n\u003ch3 data-sourcepos=\"376:1-376:65\"\u003e\n\u003cspan id=\"案3フェッチ順序の動的切り替え未実装\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A1%883%E3%83%95%E3%82%A7%E3%83%83%E3%83%81%E9%A0%86%E5%BA%8F%E3%81%AE%E5%8B%95%E7%9A%84%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E6%9C%AA%E5%AE%9F%E8%A3%85\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e案3：フェッチ順序の動的切り替え（未実装）\u003c/h3\u003e\n\u003cp data-sourcepos=\"378:1-379:56\"\u003epush-down 後のレコード数が少ない方のテーブルを先にフェッチし、\u003cbr\u003e\nそのキーを ON 最適化の IN 句に利用する。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"381:1-389:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e例: 顧客ランク='A' → 5件、商談フェーズ=... → 200件\n  現状: APP4148(5件) → キー5個 → APP4149(IN 1回) ← すでに効率的\n  動的切替の効果は限定的\n\n例: 顧客ランク='A' → 500件、商談フェーズ=... → 10件\n  現状: APP4148(500件) → キー500個 → ON 最適化フォールバック → 全件取得\n  動的切替: APP4149(10件)を先にフェッチ → キー10個 → APP4148(IN 1回) ← 大幅削減\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"391:1-392:113\"\u003e\u003cstrong\u003e効果：\u003c/strong\u003e どちらの条件が弱くても最適な方向でフェッチできる\u003cbr\u003e\n\u003cstrong\u003e課題：\u003c/strong\u003e 実際のレコード数は取得前に不明（推定ロジックが必要）、実装コスト高\u003c/p\u003e\n\u003chr data-sourcepos=\"394:1-395:0\"\u003e\n\u003ch2 data-sourcepos=\"396:1-396:30\"\u003e\n\u003cspan id=\"実装後の動作まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E5%BE%8C%E3%81%AE%E5%8B%95%E4%BD%9C%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装後の動作まとめ\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"398:1-398:48\"\u003e\n\u003cspan id=\"push-down-条件あり案1案2-適用\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#push-down-%E6%9D%A1%E4%BB%B6%E3%81%82%E3%82%8A%E6%A1%881%E6%A1%882-%E9%81%A9%E7%94%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003epush-down 条件あり（案1+案2 適用）\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"400:1-405:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eAPP4148 fetch (顧客ランク in (\"A\"))     ─┐\nAPP4149 fetch (商談フェーズ in (...))   ─┘ 並列\n                                          ↓\n                               JavaScript で JOIN（ON 条件）\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ctable data-sourcepos=\"407:1-410:53\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"407:1-407:37\"\u003e\n\u003cth data-sourcepos=\"407:2-407:2\"\u003e\u003c/th\u003e\n\u003cth data-sourcepos=\"407:4-407:24\"\u003eAPI 呼び出し数\u003c/th\u003e\n\u003cth data-sourcepos=\"407:26-407:36\"\u003e並列性\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"409:1-409:72\"\u003e\n\u003ctd data-sourcepos=\"409:2-409:16\"\u003ev1.1.1 以前\u003c/td\u003e\n\u003ctd data-sourcepos=\"409:18-409:62\"\u003e1（main）+ 最大6（JOIN チャンク）\u003c/td\u003e\n\u003ctd data-sourcepos=\"409:64-409:71\"\u003e直列\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"410:1-410:53\"\u003e\n\u003ctd data-sourcepos=\"410:2-410:16\"\u003ev1.1.2 以降\u003c/td\u003e\n\u003ctd data-sourcepos=\"410:18-410:43\"\u003e1（main）+ 1（JOIN）\u003c/td\u003e\n\u003ctd data-sourcepos=\"410:45-410:52\"\u003e並列\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 data-sourcepos=\"412:1-412:53\"\u003e\n\u003cspan id=\"push-down-条件なしon-最適化を維持\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#push-down-%E6%9D%A1%E4%BB%B6%E3%81%AA%E3%81%97on-%E6%9C%80%E9%81%A9%E5%8C%96%E3%82%92%E7%B6%AD%E6%8C%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003epush-down 条件なし（ON 最適化を維持）\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"414:1-416:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eAPP4148 fetch → キー収集 → APP4149(IN チャンク × N 回)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"418:1-418:99\"\u003eON 最適化の恩恵（絞り込み）が活きるため、従来通りの動作を維持する。\u003c/p\u003e\n\u003chr data-sourcepos=\"420:1-421:0\"\u003e\n\u003ch2 data-sourcepos=\"422:1-422:43\"\u003e\n\u003cspan id=\"push-down-できる条件の判定基準\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#push-down-%E3%81%A7%E3%81%8D%E3%82%8B%E6%9D%A1%E4%BB%B6%E3%81%AE%E5%88%A4%E5%AE%9A%E5%9F%BA%E6%BA%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003epush-down できる条件の判定基準\u003c/h2\u003e\n\u003ctable data-sourcepos=\"424:1-435:87\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"424:1-424:47\"\u003e\n\u003cth data-sourcepos=\"424:2-424:18\"\u003e条件の種類\u003c/th\u003e\n\u003cth data-sourcepos=\"424:20-424:37\"\u003epush-down 可否\u003c/th\u003e\n\u003cth data-sourcepos=\"424:39-424:46\"\u003e理由\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"426:1-426:97\"\u003e\n\u003ctd data-sourcepos=\"426:2-426:53\"\u003e\n\u003ccode\u003ea.field = value\u003c/code\u003e / \u003ccode\u003e!=\u003c/code\u003e / \u003ccode\u003e\u0026gt;\u003c/code\u003e / \u003ccode\u003e\u0026lt;\u003c/code\u003e / \u003ccode\u003e\u0026gt;=\u003c/code\u003e / \u003ccode\u003e\u0026lt;=\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-sourcepos=\"426:55-426:63\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"426:65-426:96\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"427:1-427:67\"\u003e\n\u003ctd data-sourcepos=\"427:2-427:23\"\u003e\u003ccode\u003ea.field LIKE value\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"427:25-427:33\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"427:35-427:66\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"428:1-428:71\"\u003e\n\u003ctd data-sourcepos=\"428:2-428:27\"\u003e\u003ccode\u003ea.field NOT LIKE value\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"428:29-428:37\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"428:39-428:70\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"429:1-429:65\"\u003e\n\u003ctd data-sourcepos=\"429:2-429:21\"\u003e\u003ccode\u003ea.field IN (...)\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"429:23-429:31\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"429:33-429:64\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"430:1-430:69\"\u003e\n\u003ctd data-sourcepos=\"430:2-430:25\"\u003e\u003ccode\u003ea.field NOT IN (...)\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"430:27-430:35\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"430:37-430:68\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"431:1-431:78\"\u003e\n\u003ctd data-sourcepos=\"431:2-431:34\"\u003e\u003ccode\u003ea.field IS NULL / IS NOT NULL\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"431:36-431:44\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"431:46-431:77\"\u003ekintone API サポート済み\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"432:1-432:84\"\u003e\n\u003ctd data-sourcepos=\"432:2-432:41\"\u003e\n\u003ccode\u003eAND\u003c/code\u003e（同一テーブルの条件）\u003c/td\u003e\n\u003ctd data-sourcepos=\"432:43-432:51\"\u003e✅ 可\u003c/td\u003e\n\u003ctd data-sourcepos=\"432:53-432:83\"\u003e分割して各 API に適用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"433:1-433:99\"\u003e\n\u003ctd data-sourcepos=\"433:2-433:49\"\u003e\n\u003ccode\u003eOR\u003c/code\u003e（異なるテーブルにまたがる）\u003c/td\u003e\n\u003ctd data-sourcepos=\"433:51-433:62\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"433:64-433:98\"\u003e分離すると結果が変わる\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"434:1-434:98\"\u003e\n\u003ctd data-sourcepos=\"434:2-434:49\"\u003e\n\u003ccode\u003ea.field = b.field\u003c/code\u003e（クロステーブル）\u003c/td\u003e\n\u003ctd data-sourcepos=\"434:51-434:62\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"434:64-434:97\"\u003eJOIN 後でないと評価不可\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"435:1-435:87\"\u003e\n\u003ctd data-sourcepos=\"435:2-435:49\"\u003e\n\u003ccode\u003eUPPER(a.field) = value\u003c/code\u003e 等（関数付き）\u003c/td\u003e\n\u003ctd data-sourcepos=\"435:51-435:62\"\u003e❌ 不可\u003c/td\u003e\n\u003ctd data-sourcepos=\"435:64-435:86\"\u003ekintone API 非対応\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp data-sourcepos=\"437:1-437:73\"\u003e\u003cstrong\u003e原則：\u003ccode\u003ewhereToKintone\u003c/code\u003e が変換できる演算子 = push down 可\u003c/strong\u003e\u003c/p\u003e\n\u003chr data-sourcepos=\"439:1-440:0\"\u003e\n\u003ch2 data-sourcepos=\"441:1-441:21\"\u003e\n\u003cspan id=\"関連ファイル\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E9%96%A2%E9%80%A3%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e関連ファイル\u003c/h2\u003e\n\u003ctable data-sourcepos=\"443:1-448:107\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"443:1-443:25\"\u003e\n\u003cth data-sourcepos=\"443:2-443:15\"\u003eファイル\u003c/th\u003e\n\u003cth data-sourcepos=\"443:17-443:24\"\u003e役割\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"445:1-445:93\"\u003e\n\u003ctd data-sourcepos=\"445:2-445:52\"\u003e\u003ccode\u003esrc/core/optimization/wherePredicatePushdown.ts\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"445:54-445:92\"\u003epush-down 条件の分離ロジック\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"446:1-446:111\"\u003e\n\u003ctd data-sourcepos=\"446:2-446:47\"\u003e\n\u003ccode\u003esrc/execute.ts\u003c/code\u003e — \u003ccode\u003eexecuteFullScanSelect\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-sourcepos=\"446:49-446:110\"\u003eテーブルごとの条件計算・並列フェッチ制御\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"447:1-447:107\"\u003e\n\u003ctd data-sourcepos=\"447:2-447:54\"\u003e\n\u003ccode\u003esrc/execute.ts\u003c/code\u003e — \u003ccode\u003efetchTableRecordsForFullScan\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-sourcepos=\"447:56-447:106\"\u003epush-down 条件を kintone query に組み込む\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"448:1-448:107\"\u003e\n\u003ctd data-sourcepos=\"448:2-448:57\"\u003e\n\u003ccode\u003esrc/execute.ts\u003c/code\u003e — \u003ccode\u003etryFetchJoinRecordsBySourceKeys\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-sourcepos=\"448:59-448:106\"\u003eON 最適化（push-down なし時に使用）\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n","body":"[kintone でSQL実行しよう その１０（cli対応）](https://qiita.com/rex0220/items/a2f26c8931c4802ad1b7)の続きです。\n\n# 概要\n\nJOIN 時のレコード取得条件が気になったので改善してみます。\nどちらもレコード数が多い場合に、パフォーマンスに影響します。\n今回は、Claude Code で対応しました。\n手順書を作って、実装するとわかりやすい気がする。\n週間制限がリセットされると使わないともったいない気がするのは、ただの貧乏性ですね。\n\n[kintone-sql-tools](https://github.com/rex0220/kintone-sql-tools) V1.1.2 で公開済み\n\n- WHERE 条件 Push Down（JOIN 時のレコード取得最適化）\n\n![2026-04-26_12h21_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/95928e41-5aa2-4bb5-a7db-b232522c4fc8.png)\n\n- ON 条件で、REST API 呼び出し増大\n\n![2026-04-26_12h19_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/33c997e1-2ff7-42f7-b96c-cc2feb0116b0.png)\n\n\n# WHERE 条件 Push Down（JOIN 時のレコード取得最適化）\n\n## 背景\n\nJOIN クエリは現状 `FULL_SCAN` モードで実行され、各テーブルのレコードを全件取得したあと\nJavaScript 側で WHERE フィルタを適用している。\n\n```sql\nSELECT a.顧客No, a.会社名, a.顧客ランク,\n       b.案件No_, b.案件名, b.商談フェーズ, b.売上\nFROM APP4148 AS a\nINNER JOIN APP4149 AS b ON a.顧客No = b.顧客No_\nWHERE b.商談フェーズ IN ('提案中', '内示', '受注')\n  AND a.顧客ランク IN ('A')\nORDER BY b.案件No_ DESC\n```\n\n現在の EXPLAIN 出力：\n\n```\nmode: FULL_SCAN\nreason: JOIN あり\napp: APP4148 AS a (4148)\nkintone query: (全件取得)\nfields: 顧客No, 会社名, 顧客ランク\nJOIN: APP4149 AS b (4149)\nkintone query: (全件取得)\nfields: 案件No_, 案件名, 商談フェーズ, 売上, 顧客No_\n```\n\n## 目標\n\nWHERE 条件を各テーブルへ分解（Predicate Pushdown）し、\nkintone API の query パラメータに乗せて必要なレコードのみ取得する。\n\n目標の EXPLAIN 出力：\n\n```\nmode: FULL_SCAN\nreason: JOIN あり\napp: APP4148 AS a (4148)\nkintone query: 顧客ランク in (\"A\")\nfields: 顧客No, 会社名, 顧客ランク\nJOIN: APP4149 AS b (4149)\nkintone query: 商談フェーズ in (\"提案中\",\"内示\",\"受注\")\nfields: 案件No_, 案件名, 商談フェーズ, 売上, 顧客No_\n```\n\n## Push Down 可否の判定基準\n\n| 条件の種類 | 判定 | 理由 |\n|---|---|---|\n| `a.field = value` / `!=` / `\u003e` / `\u003c` / `\u003e=` / `\u003c=` | ✅ 可 | kintone API サポート済み |\n| `a.field LIKE value` | ✅ 可 | kintone API サポート済み |\n| `a.field NOT LIKE value` | ✅ 可 | kintone API サポート済み |\n| `a.field IN (...)` | ✅ 可 | kintone API サポート済み |\n| `a.field NOT IN (...)` | ✅ 可 | kintone API サポート済み |\n| `a.field IS NULL / IS NOT NULL` | ✅ 可 | kintone API サポート済み |\n| `AND` の両辺が同一テーブル | ✅ 可 | 分割して各 API に適用できる |\n| `OR` の両辺が異なるテーブル | ❌ 不可 | 分離すると結果が変わる |\n| `a.field = b.field`（クロステーブル） | ❌ 不可 | JOIN 後でないと評価できない |\n| `UPPER(a.field) = value` 等（関数付き） | ❌ 不可 | kintone API 非対応 |\n\n\u003e **原則**：`whereToKintone` が変換できる演算子 = push down 可\n\n## 実装ステップ\n\n---\n\n### Step 1：条件分離ロジック作成\n\n**新規ファイル**：`src/core/optimization/wherePredicatePushdown.ts`\n\n#### 実装する関数\n\n```typescript\n/**\n * WHERE 式からテーブルエイリアスに対応する push down 可能な条件を抽出する。\n * 抽出できない（クロステーブル・OR・関数付き）条件は null を返す。\n */\nexport function extractTableCondition(\n  where: WhereExpr,\n  tableAlias: string\n): WhereExpr | null\n```\n\n#### アルゴリズム\n\n```\nextractTableCondition(expr, alias):\n  BINARY / NULL_CHECK:\n    → 参照フィールドが alias のみ かつ 関数なし → そのまま返す\n    → それ以外 → null\n\n  LOGICAL AND:\n    left  = extractTableCondition(left,  alias)\n    right = extractTableCondition(right, alias)\n    → both non-null : AND(left, right) を返す\n    → one non-null  : non-null 側を返す\n    → both null     : null を返す\n\n  LOGICAL OR:\n    → 両辺が異なるテーブルを参照する可能性 → null を返す（安全側）\n\n  NOT / GROUP:\n    → null を返す（複雑化を避け JavaScript 側に委ねる）\n```\n\n#### 呼び出しイメージ\n\n```typescript\n// WHERE 全体から各テーブル用の条件を取り出す\nconst condA = extractTableCondition(stmt.where, \"a\");\n// → BinaryExpr { op: \"IN\", left: a.顧客ランク, right: [\"A\"] }\n\nconst condB = extractTableCondition(stmt.where, \"b\");\n// → BinaryExpr { op: \"IN\", left: b.商談フェーズ, right: [\"提案中\",\"内示\",\"受注\"] }\n```\n\n#### テスト項目\n\n- `AND` でつながれた異なるテーブルの条件が正しく分離される\n- `OR` でつながれた条件は push down されない\n- クロステーブル条件（`a.field = b.field`）は push down されない\n- 関数付き条件（`UPPER(a.field)`）は push down されない\n- エイリアスなし条件（`field = value`、JOIN なし相当）の扱い\n\n---\n\n### Step 2：`whereToKintone` のエイリアス対応確認・修正\n\n**ファイル**：`src/converter/whereToKintone.ts`\n\n#### 確認内容\n\n`a.顧客ランク IN ('A')` のように `FieldRef.tableAlias` が付いた条件を\n`whereToKintone` に渡したとき、kintone query 文字列として正しく出力されるか確認する。\n\n期待する変換：\n\n```\na.顧客ランク in (\"A\")  →  顧客ランク in (\"A\")   ← エイリアスを除去\n```\n\n#### 修正方針\n\n`FieldRef` 処理箇所でエイリアスを除いたフィールド名のみを使用するよう修正する（既に対応済みの場合はスキップ）。\n\n---\n\n### Step 3：`execute.ts` に push down を組み込む\n\n**ファイル**：`src/execute.ts`\n\n#### 変更箇所 1：`executeFullScanSelect`（push down 条件の計算）\n\n```typescript\n// executeFullScanSelect の冒頭で各テーブルの push down 条件を計算\nconst tableConditions = new Map\u003cstring, WhereExpr\u003e();\n\nif (stmt.where !== null) {\n  const mainAlias = stmt.from.alias ?? String(stmt.from.appId);\n  const cond = extractTableCondition(stmt.where, mainAlias);\n  if (cond) tableConditions.set(mainAlias, cond);\n\n  for (const join of stmt.joins) {\n    const joinAlias = join.table.alias ?? String(join.table.appId);\n    const cond = extractTableCondition(stmt.where, joinAlias);\n    if (cond) tableConditions.set(joinAlias, cond);\n  }\n}\n```\n\n#### 変更箇所 2：`fetchTableRecordsForFullScan`（main テーブルへの適用）\n\n```typescript\n// 現状: JOIN ありの場合 WHERE を API に渡さない\n// 変更後: push down 条件が存在すれば kintone query に追加\nconst pushDownCond = tableConditions.get(mainAlias) ?? null;\nconst query = buildFetchQuery(stmt, table.appId, pushDownCond);\n```\n\n#### 変更箇所 3：`tryFetchJoinRecordsBySourceKeys`（JOIN テーブルへの適用）\n\n```typescript\n// 既存: \"joinField in (v1, v2, ...)\" を生成\n// 変更後: push down 条件がある場合は AND で結合\n// \"joinField in (v1, v2, ...) and 商談フェーズ in (\"提案中\",\"内示\",\"受注\")\"\nconst pushDownCond = tableConditions.get(joinAlias) ?? null;\nconst combinedQuery = pushDownCond\n  ? `${inClause} and ${whereToKintone(pushDownCond)}`\n  : inClause;\n```\n\n\u003e JavaScript 側の `applyFilter`（全件 WHERE 評価）は **そのまま維持**する。\n\u003e push down は絞り込みの最適化であり、結果の正確性は JavaScript 側フィルタが保証する。\n\n---\n\n### Step 4：EXPLAIN 表示の更新\n\n**ファイル**：`src/core/optimization/sharedPlanner.js`\n\npush down 後の実際の kintone query を EXPLAIN に反映する。\n\n```\n変更前: kintone query: (全件取得)\n変更後: kintone query: 顧客ランク in (\"A\")\n```\n\npush down 条件がない場合は引き続き `(全件取得)` と表示する。\n\n---\n\n### Step 5：統合テスト・動作確認\n\n#### 確認するクエリパターン\n\n| パターン | push down | 期待動作 |\n|---|---|---|\n| AND で各テーブル条件が分離できる | ✅ 両テーブルへ | レコード取得数が減少 |\n| OR でつながれた条件 | ❌ 不可 | 全件取得のまま（正確性維持） |\n| クロステーブル条件のみ | ❌ 不可 | 全件取得のまま |\n| WHERE なし | — | 変化なし |\n| main テーブルのみ条件あり | ✅ main のみ | JOIN テーブルは全件取得 |\n\n#### 結果の正確性確認\n\npush down あり / なし で同一クエリの結果行が一致することを確認する。\n\n---\n\n## 修正ファイル一覧\n\n| ファイル | 種別 | 内容 |\n|---|---|---|\n| `src/core/optimization/wherePredicatePushdown.ts` | 新規 | 条件分離ロジック |\n| `src/converter/whereToKintone.ts` | 修正（要確認） | エイリアス除去対応 |\n| `src/execute.ts` | 修正 | push down 条件の計算・適用 |\n| `src/core/optimization/sharedPlanner.js` | 修正 | EXPLAIN 表示更新 |\n\n## ブランチ・マージ手順\n\n```bash\n# 作業ブランチ（作成済み）\ngit checkout perf/where-pushdown-join\n\n# 各ステップをコミット\ngit add src/core/optimization/wherePredicatePushdown.ts\ngit commit -m \"perf: add WHERE predicate pushdown extraction logic\"\n\ngit add src/converter/whereToKintone.ts\ngit commit -m \"perf: strip table alias in whereToKintone for pushdown\"\n\ngit add src/execute.ts\ngit commit -m \"perf: apply per-table WHERE conditions to kintone API calls\"\n\ngit add src/core/optimization/sharedPlanner.js\ngit commit -m \"perf: show pushed-down kintone query in EXPLAIN output\"\n\n# PR 作成\ngit push -u origin perf/where-pushdown-join\ngh pr create --title \"perf: WHERE predicate pushdown for JOIN queries\"\n```\n\n\n# ON 条件による REST API 呼び出し増大：原因と対策\n\n## 背景\n\nJOIN クエリは kintone API が直接サポートしないため、FULL_SCAN モードで実行される。\n各テーブルを個別に API から取得し、JavaScript 側で結合・フィルタする構成になっている。\n\n---\n\n## 原因：ON 最適化のチャンク分割\n\n### ON 最適化とは\n\nJOIN 先テーブルの全件取得を避けるため、結合キーの値セットを IN 句として API に渡す最適化。\n\n```sql\nSELECT a.顧客No, a.会社名, b.案件名\nFROM APP4148 AS a\nINNER JOIN APP4149 AS b ON a.顧客No = b.顧客No_\nWHERE b.商談フェーズ IN ('提案中', '内示', '受注')\n  AND a.顧客ランク IN ('A')\n```\n\n```\n① APP4148 を全件取得（顧客ランク フィルタあり）\n② ①の結果から 顧客No_ のユニーク値を収集\n③ APP4149 に IN 句で絞り込みリクエスト\n   → 顧客No_ in (\"v1\",\"v2\",...,\"v50\")   ← 50件ずつチャンク\n```\n\n### チャンク上限\n\n| 定数 | 値 | 意味 |\n|---|---|---|\n| `JOIN_IN_CHUNK_SIZE` | 50 | 1リクエストあたりの IN 値数 |\n| `JOIN_IN_MAX_CHUNKS` | 6 | 最大チャンク数 |\n| `JOIN_IN_MAX_KEYS` | 300 | ON 最適化の上限キー数 |\n\n### 問題：キー数に比例して API 呼び出しが増える\n\n| 顧客ランク='A' の顧客数 | ON 最適化の挙動 | API 呼び出し数（APP4149） |\n|---|---|---|\n| 〜50件 | 1チャンク | 1回 |\n| 51〜100件 | 2チャンク | 2回 |\n| 151〜300件 | 最大6チャンク | 6回 |\n| **300件超** | **フォールバック（全件取得）** | **案件数 / 500 回** |\n\n300件超でフォールバックが発生すると、APP4149 に10万件ある場合は\n**200回以上の API 呼び出し**が発生する。\n\n### 実際の API リクエスト例（300件超フォールバック時の警告）\n\n```\nJOINキーが 312 件のため ON 最適化をスキップし、JOIN先を全件取得します（上限 300 件）。\n```\n\n---\n\n## 対策\n\n### 案1：push-down 条件がある JOIN テーブルは ON 最適化をスキップ ✅ 実装済み\n\nJOIN テーブルに WHERE push-down 条件がある場合、ON 最適化（IN 句チャンク）を使わず\npush-down 条件のみで直接フェッチする。\n\n```\nBefore: APP4148(filtered) → キー収集 → APP4149(IN×N回)\nAfter:  APP4149(push-down のみ) ← 1回のフェッチで完結\n```\n\n**効果：** push-down 条件が絞り込める場合は API 呼び出しが大幅に減少  \n**限界：** push-down 後の JOIN テーブルが大量レコードの場合は fetch 回数が増える可能性あり\n\n---\n\n### 案2：push-down ありの JOIN テーブルをメインと並列フェッチ ✅ 実装済み\n\npush-down 条件がある JOIN テーブルはメインテーブルの完了を待たず、同時にフェッチ開始する。\n\n```\nBefore: APP4148 fetch → (完了待ち) → APP4149 fetch（直列）\nAfter:  APP4148 fetch ─並列─ APP4149 fetch（並列）\n```\n\n**効果：** ウォール時間を短縮（API 回数は案1と同じ、レスポンス時間が半減に近づく）\n\n---\n\n### 案3：フェッチ順序の動的切り替え（未実装）\n\npush-down 後のレコード数が少ない方のテーブルを先にフェッチし、\nそのキーを ON 最適化の IN 句に利用する。\n\n```\n例: 顧客ランク='A' → 5件、商談フェーズ=... → 200件\n  現状: APP4148(5件) → キー5個 → APP4149(IN 1回) ← すでに効率的\n  動的切替の効果は限定的\n\n例: 顧客ランク='A' → 500件、商談フェーズ=... → 10件\n  現状: APP4148(500件) → キー500個 → ON 最適化フォールバック → 全件取得\n  動的切替: APP4149(10件)を先にフェッチ → キー10個 → APP4148(IN 1回) ← 大幅削減\n```\n\n**効果：** どちらの条件が弱くても最適な方向でフェッチできる  \n**課題：** 実際のレコード数は取得前に不明（推定ロジックが必要）、実装コスト高\n\n---\n\n## 実装後の動作まとめ\n\n### push-down 条件あり（案1+案2 適用）\n\n```\nAPP4148 fetch (顧客ランク in (\"A\"))     ─┐\nAPP4149 fetch (商談フェーズ in (...))   ─┘ 並列\n                                          ↓\n                               JavaScript で JOIN（ON 条件）\n```\n\n| | API 呼び出し数 | 並列性 |\n|---|---|---|\n| v1.1.1 以前 | 1（main）+ 最大6（JOIN チャンク） | 直列 |\n| v1.1.2 以降 | 1（main）+ 1（JOIN） | 並列 |\n\n### push-down 条件なし（ON 最適化を維持）\n\n```\nAPP4148 fetch → キー収集 → APP4149(IN チャンク × N 回)\n```\n\nON 最適化の恩恵（絞り込み）が活きるため、従来通りの動作を維持する。\n\n---\n\n## push-down できる条件の判定基準\n\n| 条件の種類 | push-down 可否 | 理由 |\n|---|---|---|\n| `a.field = value` / `!=` / `\u003e` / `\u003c` / `\u003e=` / `\u003c=` | ✅ 可 | kintone API サポート済み |\n| `a.field LIKE value` | ✅ 可 | kintone API サポート済み |\n| `a.field NOT LIKE value` | ✅ 可 | kintone API サポート済み |\n| `a.field IN (...)` | ✅ 可 | kintone API サポート済み |\n| `a.field NOT IN (...)` | ✅ 可 | kintone API サポート済み |\n| `a.field IS NULL / IS NOT NULL` | ✅ 可 | kintone API サポート済み |\n| `AND`（同一テーブルの条件） | ✅ 可 | 分割して各 API に適用 |\n| `OR`（異なるテーブルにまたがる） | ❌ 不可 | 分離すると結果が変わる |\n| `a.field = b.field`（クロステーブル） | ❌ 不可 | JOIN 後でないと評価不可 |\n| `UPPER(a.field) = value` 等（関数付き） | ❌ 不可 | kintone API 非対応 |\n\n**原則：`whereToKintone` が変換できる演算子 = push down 可**\n\n---\n\n## 関連ファイル\n\n| ファイル | 役割 |\n|---|---|\n| `src/core/optimization/wherePredicatePushdown.ts` | push-down 条件の分離ロジック |\n| `src/execute.ts` — `executeFullScanSelect` | テーブルごとの条件計算・並列フェッチ制御 |\n| `src/execute.ts` — `fetchTableRecordsForFullScan` | push-down 条件を kintone query に組み込む |\n| `src/execute.ts` — `tryFetchJoinRecordsBySourceKeys` | ON 最適化（push-down なし時に使用） |\n","coediting":false,"comments_count":0,"created_at":"2026-04-26T13:19:47+09:00","group":null,"id":"5c3248ddcbb4157f8e0e","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"SQL","versions":[]},{"name":"kintone","versions":[]},{"name":"ClaudeCode","versions":[]}],"title":"kintone でSQL実行しよう その１１（パフォーマンス改善２）","updated_at":"2026-04-26T13:19:47+09:00","url":"https://qiita.com/rex0220/items/5c3248ddcbb4157f8e0e","user":{"description":"","facebook_id":"","followees_count":0,"followers_count":150,"github_login_name":"rex0220","id":"rex0220","items_count":594,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":100572,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/100572/profile-images/1473708137","team_only":false,"twitter_screen_name":"rex02201","website_url":"https://rex0220.stores.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:380\"\u003ekintone のカスタマイズ開発を「\u003cstrong\u003eビルドは挟まない、でもエディタ上では型補完と型チェックが効く\u003c/strong\u003e」状態で進めるためのテンプレートリポジトリ \u003ca href=\"https://github.com/goqoo-on-kintone/mr-satan\" rel=\"nofollow noopener\" target=\"_blank\"\u003eMr. Satan\u003c/a\u003e を公開しました。GitHub の「Use this template」からそのまま派生リポジトリを作って使えます。\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-3:172\"\u003e本記事ではこのテンプレートの位置づけと、核となる「\u003ccode\u003e.js\u003c/code\u003e から \u003ccode\u003etypes.ts\u003c/code\u003e を JSDoc で参照する」パターンを具体例で解説します。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"5:1-5:55\"\u003e\n\u003cspan id=\"kintone-カスタマイズの現実2-つの極端\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone-%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E3%81%AE%E7%8F%BE%E5%AE%9F2-%E3%81%A4%E3%81%AE%E6%A5%B5%E7%AB%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone カスタマイズの現実：2 つの極端\u003c/h2\u003e\n\u003cp data-sourcepos=\"7:1-7:98\"\u003ekintone のカスタマイズ開発には、大きく分けて 2 つの方向性があります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"9:1-9:60\"\u003e\n\u003cspan id=\"1-webpack-などでバンドルしてアップロード\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-webpack-%E3%81%AA%E3%81%A9%E3%81%A7%E3%83%90%E3%83%B3%E3%83%89%E3%83%AB%E3%81%97%E3%81%A6%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. webpack などでバンドルしてアップロード\u003c/h3\u003e\n\u003cp data-sourcepos=\"11:1-11:419\"\u003eTypeScript・最新 JS 構文・npm エコシステムをフル活用できる反面、kintone にアップロードされるのはバンドル後の成果物。そのコードを直接編集することは事実上不可能で、開発環境を持っている担当者でないと手を入れられません。拙作 \u003ca href=\"https://github.com/goqoo-on-kintone/goqoo\" rel=\"nofollow noopener\" target=\"_blank\"\u003eGoqoo on kintone\u003c/a\u003e はこの方向性の代表例です。\u003c/p\u003e\n\u003cp data-sourcepos=\"13:1-13:153\"\u003e本格開発には最適ですが、「定数を一文字書き換えたい」だけでも再ビルド・再アップロードが必要になります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"15:1-15:53\"\u003e\n\u003cspan id=\"2-素の-js-をそのままアップロード\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E7%B4%A0%E3%81%AE-js-%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. 素の \u003ccode\u003e.js\u003c/code\u003e をそのままアップロード\u003c/h3\u003e\n\u003cp data-sourcepos=\"17:1-17:269\"\u003ekintone 上で直接編集できるので手軽ですが、型補完・型チェック・モジュール分割といったモダンな開発体験は諦めることになります。フィールド名をタイポしてもエディタは何も教えてくれません。\u003c/p\u003e\n\u003chr data-sourcepos=\"19:1-20:0\"\u003e\n\u003cp data-sourcepos=\"21:1-21:270\"\u003eどちらも一長一短で、「納品後に顧客側で定数を差し替えてほしい」「保守契約なしで納品完結する案件」のようなシチュエーションでは、前者は過剰で、後者は辛い、という状態が続いていました。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"23:1-23:71\"\u003e\n\u003cspan id=\"3-つ目の選択肢型は書くただしビルドはしない\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E3%81%A4%E7%9B%AE%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E5%9E%8B%E3%81%AF%E6%9B%B8%E3%81%8F%E3%81%9F%E3%81%A0%E3%81%97%E3%83%93%E3%83%AB%E3%83%89%E3%81%AF%E3%81%97%E3%81%AA%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3 つ目の選択肢：型は書く、ただしビルドはしない\u003c/h2\u003e\n\u003cp data-sourcepos=\"25:1-25:64\"\u003eMr. Satan はその中間を狙ったテンプレートです。\u003c/p\u003e\n\u003cul data-sourcepos=\"27:1-31:0\"\u003e\n\u003cli data-sourcepos=\"27:1-27:127\"\u003e\n\u003ccode\u003e.js\u003c/code\u003e をビルドせず\u003cstrong\u003eそのまま kintone にアップロード\u003c/strong\u003e → kintone 上で直接編集できる余地を残す\u003c/li\u003e\n\u003cli data-sourcepos=\"28:1-28:179\"\u003e開発中は \u003ccode\u003etypes.ts\u003c/code\u003e に型定義を書き、\u003ccode\u003e.js\u003c/code\u003e からは \u003cstrong\u003eJSDoc の \u003ccode\u003e@type {import('./types').Foo}\u003c/code\u003e\u003c/strong\u003e で参照 → VS Code 上では型補完・型チェックが効く\u003c/li\u003e\n\u003cli data-sourcepos=\"29:1-29:98\"\u003eビルド工程がないので「ソースと本番の同期ズレ」が原理的に起きない\u003c/li\u003e\n\u003cli data-sourcepos=\"30:1-31:0\"\u003enpmでのscaffoldはあえて採用せず、戦闘力低めのGitHubテンプレートに留めた\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"32:1-32:104\"\u003e以降、この仕組みのコアとなる \u003ccode\u003etypes.ts\u003c/code\u003e + JSDoc 参照を具体例で見ていきます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"34:1-34:64\"\u003e\n\u003cspan id=\"具体例js-から-typests-を-jsdoc-で参照する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%85%B7%E4%BD%93%E4%BE%8Bjs-%E3%81%8B%E3%82%89-typests-%E3%82%92-jsdoc-%E3%81%A7%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e具体例：\u003ccode\u003e.js\u003c/code\u003e から \u003ccode\u003etypes.ts\u003c/code\u003e を JSDoc で参照する\u003c/h2\u003e\n\u003cp data-sourcepos=\"36:1-36:179\"\u003eテンプレートに同梱されているサンプルアプリ（\u003ccode\u003esrc/apps/sample1/\u003c/code\u003e）を題材に、フィールド型定義から JSDoc 参照までの流れを追います。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"38:1-38:55\"\u003e\n\u003cspan id=\"step-1-trunks-でフィールド型を生成する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-1-trunks-%E3%81%A7%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%9E%8B%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 1: trunks でフィールド型を生成する\u003c/h3\u003e\n\u003cp data-sourcepos=\"40:1-40:319\"\u003ekintone のアプリからフィールド型定義を自動生成するのに、拙作 \u003ca href=\"https://github.com/goqoo-on-kintone/trunks\" rel=\"nofollow noopener\" target=\"_blank\"\u003e\u003ccode\u003e@goqoo/trunks\u003c/code\u003e\u003c/a\u003e を使います。\u003ccode\u003e@kintone/dts-gen\u003c/code\u003e のラッパーで、\u003ccode\u003etrunks.config.ts\u003c/code\u003e に複数アプリを登録しておくと一発で全アプリの型を出力できます。\u003c/p\u003e\n\u003cp data-sourcepos=\"42:1-42:238\"\u003etrunks 自体について詳しくは別記事 \u003ca href=\"https://qiita.com/the_red/items/3ae726a7eed2d03dc794\" id=\"reference-16d44f893430818e9fc5\"\u003e@kintone/dts-gen を複数アプリで一括実行するラッパーツール @goqoo/trunks を作った\u003c/a\u003e を参照してください。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"44:1-55:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// trunks.config.ts\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003edefineConfig\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003efrom\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e@goqoo/trunks\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e \u003cspan class=\"nf\"\u003edefineConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n  \u003cspan class=\"na\"\u003ehost\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eyour-subdomain.cybozu.com\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"na\"\u003eapps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"na\"\u003esample1\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n  \u003cspan class=\"na\"\u003eauth\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"na\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003epassword\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"57:1-57:89\"\u003e\u003ccode\u003enpx @goqoo/trunks\u003c/code\u003e を実行すると \u003ccode\u003edts/sample1-fields.d.ts\u003c/code\u003e が生成されます。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"59:1-74:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// dts/sample1-fields.d.ts（抜粋）\u003c/span\u003e\n\u003cspan class=\"kr\"\u003edeclare\u003c/span\u003e \u003cspan class=\"k\"\u003enamespace\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etypes\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"kr\"\u003einterface\u003c/span\u003e \u003cspan class=\"nx\"\u003eSample1Fields\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003e件名\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efieldTypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eSingleLineText\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003e本文\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efieldTypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eMultiLineText\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003e担当者\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efieldTypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eUserSelect\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003e期日\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efieldTypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nb\"\u003eDate\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n  \u003cspan class=\"kr\"\u003einterface\u003c/span\u003e \u003cspan class=\"nx\"\u003eSavedSample1Fields\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"nx\"\u003eSample1Fields\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003e$id\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efieldTypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eId\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003e$revision\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efieldTypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eRevision\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"c1\"\u003e// ... システムフィールド一式\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"76:1-76:151\"\u003eここで生成されるのは \u003cstrong\u003ekintone 側のフィールド定義そのもの\u003c/strong\u003e。日本語のフィールド名もそのまま型になります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"78:1-78:59\"\u003e\n\u003cspan id=\"step-2-typests-でイベント型を組み立てる\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-2-typests-%E3%81%A7%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%9E%8B%E3%82%92%E7%B5%84%E3%81%BF%E7%AB%8B%E3%81%A6%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 2: \u003ccode\u003etypes.ts\u003c/code\u003e でイベント型を組み立てる\u003c/h3\u003e\n\u003cp data-sourcepos=\"80:1-80:359\"\u003ekintone のイベント型は 2 層に分けて管理します。汎用的な部分（kintone 側の共通構造）は \u003cstrong\u003e全アプリ共通の \u003ccode\u003esrc/types.ts\u003c/code\u003e\u003c/strong\u003e に一度だけ書き、\u003cstrong\u003e各アプリの \u003ccode\u003esrc/apps/{app}/types.ts\u003c/code\u003e\u003c/strong\u003e はそこから \u003ccode\u003eimport type\u003c/code\u003e で引き込んでアプリ固有のレコード型を食わせるだけ、という二段構え。\u003c/p\u003e\n\u003cp data-sourcepos=\"82:1-82:16\"\u003eまず汎用側:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"84:1-115:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// src/types.ts\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eKintoneEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"na\"\u003eappId\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e?:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eIndexEvent\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nx\"\u003eT\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eKintoneEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"na\"\u003erecords\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003eviewType\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003elist\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ecalendar\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003ecustom\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003eviewId\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003eviewName\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003eoffset\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003enumber\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003enumber\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003edate\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eDetailEvent\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nx\"\u003eT\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eKintoneEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"na\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003erecordId\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003ereuse\u003c/span\u003e\u003cspan class=\"p\"\u003e?:\u003c/span\u003e \u003cspan class=\"nx\"\u003eboolean\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eSubmitEvent\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nx\"\u003eT\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eKintoneEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"na\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eT\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n  \u003cspan class=\"nl\"\u003echanges\u003c/span\u003e\u003cspan class=\"p\"\u003e?:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n    \u003cspan class=\"na\"\u003efield\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"na\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nl\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003eunknown\u003c/span\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n    \u003cspan class=\"nl\"\u003erow\u003c/span\u003e\u003cspan class=\"p\"\u003e?:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"na\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nl\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nb\"\u003eRecord\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kr\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eunknown\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"117:1-117:25\"\u003e次にアプリ固有側:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"typescript\" data-sourcepos=\"119:1-130:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// src/apps/sample1/types.ts\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003eIndexEvent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eDetailEvent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eSubmitEvent\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003efrom\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e../../types\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// Step 1 で生成された型を流用\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eSample1Record\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etypes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eSavedSample1Fields\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// イベント型はレコード型を食わせるだけ\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eSample1IndexEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eIndexEvent\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nx\"\u003eSample1Record\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eSample1DetailEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eDetailEvent\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nx\"\u003eSample1Record\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e \u003cspan class=\"kd\"\u003etype\u003c/span\u003e \u003cspan class=\"nx\"\u003eSample1SubmitEvent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eSubmitEvent\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nx\"\u003eSample1Record\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"132:1-132:355\"\u003eアプリの \u003ccode\u003etypes.ts\u003c/code\u003e が薄く保てるのがポイント。アプリが 10 個あっても、kintone のイベント構造の定義は \u003ccode\u003esrc/types.ts\u003c/code\u003e に一度書けば使い回せます。新規アプリを追加するときも、アプリ側に書くのは「レコード型を食わせたイベント型のエイリアス」だけで済みます。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"134:1-134:61\"\u003e\n\u003cspan id=\"step-3-js-から-jsdoc-で-typests-を参照する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#step-3-js-%E3%81%8B%E3%82%89-jsdoc-%E3%81%A7-typests-%E3%82%92%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eStep 3: \u003ccode\u003e.js\u003c/code\u003e から JSDoc で \u003ccode\u003etypes.ts\u003c/code\u003e を参照する\u003c/h3\u003e\n\u003cp data-sourcepos=\"136:1-136:179\"\u003eここが本題です。実装用の \u003ccode\u003e.js\u003c/code\u003e 側では、ファイル先頭に \u003ccode\u003e//@ts-check\u003c/code\u003e を付けた上で、イベントハンドラの引数に JSDoc で型を与えます。\u003c/p\u003e\n\u003cp data-sourcepos=\"138:1-138:382\"\u003e以下の例は \u003ccode\u003eedit-show.js\u003c/code\u003e の抜粋。前提として sample1 には \u003ccode\u003ecommon.js\u003c/code\u003e を 1 本置いてあり、同じアプリ内の複数ファイルから使い回したいユーティリティ（ここでは \u003ccode\u003ehasValue\u003c/code\u003e）を \u003ccode\u003ewindow.__sample1Common\u003c/code\u003e 経由で公開しています。\u003ccode\u003eedit-show.js\u003c/code\u003e はその \u003ccode\u003e__sample1Common\u003c/code\u003e から \u003ccode\u003ehasValue\u003c/code\u003e を取り出して使います。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"140:1-165:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e//@ts-check\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// src/apps/sample1/edit-show.js\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n  \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003ehasValue\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003e__sample1Common\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n  \u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eevents\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.create.show\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.edit.show\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"cm\"\u003e/** @type {import('./types').Sample1DetailEvent} */\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n      \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n      \u003cspan class=\"c1\"\u003e// 件名（SingleLineText）の value にアクセス — IDE で補完が効く\u003c/span\u003e\n      \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ehasValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003e件名\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003e本文\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edisabled\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n      \u003cspan class=\"c1\"\u003e// 期日（Date）が空なら今日の日付を入れる\u003c/span\u003e\n      \u003cspan class=\"k\"\u003eif \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nf\"\u003ehasValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003e期日\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n        \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003e期日\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eluxon\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"nf\"\u003etoFormat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eyyyy-MM-dd\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n      \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n      \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n    \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"167:1-167:306\"\u003eポイントは \u003ccode\u003e(/** @type {import('./types').Sample1DetailEvent} */ event) =\u0026gt;\u003c/code\u003e の部分。JSDoc の \u003ccode\u003e@type\u003c/code\u003e で \u003ccode\u003etypes.ts\u003c/code\u003e から \u003ccode\u003eSample1DetailEvent\u003c/code\u003e を import することで、それ以降 \u003ccode\u003eevent.record.件名.value\u003c/code\u003e のような形で\u003cstrong\u003e型補完とタイポチェックがフルに効きます\u003c/strong\u003e。\u003c/p\u003e\n\u003cp data-sourcepos=\"169:1-169:265\"\u003e実ファイルはあくまで素の \u003ccode\u003e.js\u003c/code\u003e なので、そのまま kintone にアップロードできます。ビルド成果物ではないので、アップロード後に kintone 側で直接編集して定数をいじる、といった運用も可能です。\u003c/p\u003e\n\u003cp data-sourcepos=\"171:1-171:400\"\u003e\u003ccode\u003esample1/\u003c/code\u003e アプリは \u003ccode\u003ecommon.js\u003c/code\u003e / \u003ccode\u003eedit-show.js\u003c/code\u003e / \u003ccode\u003eindex-show.js\u003c/code\u003e の 3 本構成で、これらを同じ kintone アプリの「JavaScript / CSS でカスタマイズ」に登録して使います。\u003ccode\u003ecommon.js\u003c/code\u003e は後続ファイルから参照している都合上、先頭に並べてください。この点は kintone カスタマイズ界隈で普通に行われている方法ですね。\u003c/p\u003e\n\u003cp data-sourcepos=\"173:1-173:229\"\u003eもう一つの \u003ccode\u003esample2/\u003c/code\u003e アプリは \u003ccode\u003eedit-submit.js\u003c/code\u003e だけで完結する最小構成になっています。共通ヘルパを切り出す必要がない規模のアプリでは \u003ccode\u003ecommon.js\u003c/code\u003e は省略して構いません。\u003c/p\u003e\n\u003cp data-sourcepos=\"175:1-175:406\"\u003eさらに、複数アプリ横断で使いたいユーティリティのために \u003ccode\u003esrc/global.js\u003c/code\u003e という全アプリ共通 JS も同梱しています。kintoneシステム管理の「JavaScript / CSSでカスタマイズ」で登録すると、どのアプリの JS からも \u003ccode\u003ewindow.__global\u003c/code\u003e で参照できます。ヘルパの置き場所は以下の 3 階層で使い分けるイメージです。\u003c/p\u003e\n\u003ctable data-sourcepos=\"177:1-181:98\"\u003e\n\u003cthead\u003e\n\u003ctr data-sourcepos=\"177:1-177:46\"\u003e\n\u003cth data-sourcepos=\"177:2-177:15\"\u003eスコープ\u003c/th\u003e\n\u003cth data-sourcepos=\"177:17-177:30\"\u003e置き場所\u003c/th\u003e\n\u003cth data-sourcepos=\"177:32-177:39\"\u003e参照\u003c/th\u003e\n\u003cth data-sourcepos=\"177:41-177:45\"\u003e例\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr data-sourcepos=\"179:1-179:91\"\u003e\n\u003ctd data-sourcepos=\"179:2-179:21\"\u003e全アプリ横断\u003c/td\u003e\n\u003ctd data-sourcepos=\"179:23-179:39\"\u003e\u003ccode\u003esrc/global.js\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"179:41-179:59\"\u003e\u003ccode\u003ewindow.__global\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"179:61-179:90\"\u003eログ関数 \u003ccode\u003elog(tag, ...)\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"180:1-180:111\"\u003e\n\u003ctd data-sourcepos=\"180:2-180:21\"\u003eアプリ内共通\u003c/td\u003e\n\u003ctd data-sourcepos=\"180:23-180:50\"\u003e\u003ccode\u003esrc/apps/{app}/common.js\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"180:52-180:75\"\u003e\u003ccode\u003ewindow.__{app}Common\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-sourcepos=\"180:77-180:110\"\u003esample1 の \u003ccode\u003ehasValue\u003c/code\u003e / \u003ccode\u003etoday\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr data-sourcepos=\"181:1-181:98\"\u003e\n\u003ctd data-sourcepos=\"181:2-181:30\"\u003eファイル内ローカル\u003c/td\u003e\n\u003ctd data-sourcepos=\"181:32-181:53\"\u003eIIFE ブロック内\u003c/td\u003e\n\u003ctd data-sourcepos=\"181:55-181:68\"\u003e直接参照\u003c/td\u003e\n\u003ctd data-sourcepos=\"181:70-181:97\"\u003esample2 の \u003ccode\u003eisValidEmail\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 data-sourcepos=\"183:1-183:59\"\u003e\n\u003cspan id=\"比較全部インラインの-jsdoc-で書くと\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%AF%94%E8%BC%83%E5%85%A8%E9%83%A8%E3%82%A4%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%AE-jsdoc-%E3%81%A7%E6%9B%B8%E3%81%8F%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e比較：全部インラインの JSDoc で書くと？\u003c/h3\u003e\n\u003cp data-sourcepos=\"185:1-185:203\"\u003e\u003ccode\u003etypes.ts\u003c/code\u003e + \u003ccode\u003eimport\u003c/code\u003e 方式には、「インラインで JSDoc にオブジェクト型リテラルを直接書く」という代替があります。ただしその方式は現実的に辛いです。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"187:1-194:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 悪い例：インラインで全部書こうとした場合\u003c/span\u003e\n\u003cspan class=\"nx\"\u003ekintone\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eevents\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n  \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003eapp.record.edit.show\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n  \u003cspan class=\"cm\"\u003e/** @param {{ appId: number, record: { 件名: { type: 'SINGLE_LINE_TEXT', value: string }, 本文: { type: 'MULTI_LINE_TEXT', value: string, disabled?: boolean }, 期日: { type: 'DATE', value: string } /* ... */\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e \u003cspan class=\"nx\"\u003erecordId\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nx\"\u003estring\u003c/span\u003e \u003cspan class=\"p\"\u003e}}\u003c/span\u003e \u003cspan class=\"nx\"\u003eevent\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"sr\"\u003e/\u003c/span\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eevent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"p\"\u003e...\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"196:1-196:28\"\u003eこの書き方の問題点:\u003c/p\u003e\n\u003cul data-sourcepos=\"198:1-201:0\"\u003e\n\u003cli data-sourcepos=\"198:1-198:109\"\u003e\n\u003cstrong\u003e一行が暴発する\u003c/strong\u003e。フィールド数が増えると JSDoc コメントだけで画面が埋まる\u003c/li\u003e\n\u003cli data-sourcepos=\"199:1-199:105\"\u003e\u003cstrong\u003e他のイベント（\u003ccode\u003esubmit\u003c/code\u003e、\u003ccode\u003eindex.show\u003c/code\u003e など）でも同じ型を書き直す羽目になる\u003c/strong\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"200:1-201:0\"\u003e\u003cstrong\u003eフィールド定義が変わったらすべての JSDoc を手で直さなければならない\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"202:1-202:272\"\u003e一方、\u003ccode\u003etypes.ts\u003c/code\u003e に一度だけ定義を書く方式なら、JSDoc 側は \u003ccode\u003eimport('./types').Sample1DetailEvent\u003c/code\u003e という 1 行の参照だけで済みます。\u003ccode\u003etypes.ts\u003c/code\u003e を一箇所直せば、それを import している全 \u003ccode\u003e.js\u003c/code\u003e に自動的に波及します。\u003c/p\u003e\n\u003cp data-sourcepos=\"204:1-204:104\"\u003e\u003cstrong\u003eTS で書ける部分は TS で、JSDoc は参照だけ\u003c/strong\u003e。これがこのスタイルの肝です。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"206:1-206:60\"\u003e\n\u003cspan id=\"なぜ今このスタイルが現実的になったのか\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E4%BB%8A%E3%81%93%E3%81%AE%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%8C%E7%8F%BE%E5%AE%9F%E7%9A%84%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eなぜ今このスタイルが現実的になったのか\u003c/h2\u003e\n\u003cp data-sourcepos=\"208:1-208:502\"\u003e実は \u003ccode\u003e.js\u003c/code\u003e + JSDoc + \u003ccode\u003etypes.ts\u003c/code\u003e という構成自体は何年も前に思いついていて、Goqoo on kintoneの設定ファイル \u003ca href=\"https://github.com/goqoo-on-kintone/goqoo-templates/blob/5da0fda31b3f34eabd70740580de60dd3badd7ad/templates/default/goqoo.config.js\" rel=\"nofollow noopener\" target=\"_blank\"\u003egoqoo.config.js\u003c/a\u003e / \u003ca href=\"https://github.com/goqoo-on-kintone/goqoo-templates/blob/5da0fda31b3f34eabd70740580de60dd3badd7ad/templates/default/goqoo.config.types.ts\" rel=\"nofollow noopener\" target=\"_blank\"\u003egoqoo.config.types.ts\u003c/a\u003e でもこのパターンを採用しています。\u003c/p\u003e\n\u003cp data-sourcepos=\"210:1-210:335\"\u003eしかし、ロジックを書くJSにこのパターンを適用しようとすると今まではうまく行きませんでした。シンプルな設定ファイルに比べると、変数・関数に細かく型を当てていく作業が沢山あるし、型の作りが特殊になるケースもそれなりに出てきます。\u003c/p\u003e\n\u003cp data-sourcepos=\"212:1-212:514\"\u003e\u003ccode\u003e@type {import('./types').Foo}\u003c/code\u003e の付け直しや、\u003ccode\u003etypes.ts\u003c/code\u003e 側の変更への追従といった\u003cstrong\u003eJSDoc のメンテナンスは、人手でやると地味に頭を使う作業\u003c/strong\u003eです。「この JSDoc は正しく解決されているか？」「import パスは合っているか？」と確認していく途中で気持ちが折れて、結局は「全部 TypeScript にして webpack でビルドするわ！インラインで型が書けるのサイコー！」と結論づくことばかりでした。\u003c/p\u003e\n\u003cp data-sourcepos=\"214:1-214:330\"\u003e\u003cstrong\u003eClaude Code をはじめとする生成 AI は、この種の機械的な追従作業を苦にしません\u003c/strong\u003e。むしろ得意分野です。JSDoc メンテのコスト問題が AI 側に吸収されるので、人間は「どのような型を \u003ccode\u003etypes.ts\u003c/code\u003e に置くか」という本質的な設計だけに集中できます。\u003c/p\u003e\n\u003cp data-sourcepos=\"216:1-216:403\"\u003eこのテンプレートを公開するに至った動機の一つが、まさにここにあります。以前何度か諦めたこのパターンが、AIのお陰でようやく実案件でも採用できるようになりました。そんな経緯があるので、\u003cstrong\u003eMr. Satanは生成 AI と協働する前提\u003c/strong\u003eで使うことを推奨します（もちろん人手だけでも動作します）。\u003c/p\u003e\n\u003cp data-sourcepos=\"218:1-218:392\"\u003eリポジトリには AI 向けのガイドとして \u003ca href=\"https://github.com/goqoo-on-kintone/mr-satan/blob/main/CLAUDE.md\" rel=\"nofollow noopener\" target=\"_blank\"\u003eCLAUDE.md\u003c/a\u003e を同梱してあり、Claude Code から参照される前提で規約・命名・落とし穴（\u003ccode\u003ecommon.js\u003c/code\u003e の読み込み順、\u003ccode\u003eWindow\u003c/code\u003e インターフェース拡張パターン、kintone API を推測で書かない、など）を整理しています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"220:1-220:12\"\u003e\n\u003cspan id=\"使い方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BD%BF%E3%81%84%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e使い方\u003c/h2\u003e\n\u003col data-sourcepos=\"222:1-229:0\"\u003e\n\u003cli data-sourcepos=\"222:1-222:88\"\u003eGitHub の「\u003cstrong\u003eUse this template\u003c/strong\u003e」ボタンから自分のリポジトリを作る\u003c/li\u003e\n\u003cli data-sourcepos=\"223:1-223:16\"\u003e\u003ccode\u003enpm install\u003c/code\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"224:1-224:83\"\u003e\n\u003ccode\u003e.ginuerc.js\u003c/code\u003e のドメインと \u003ccode\u003eappId\u003c/code\u003e を実プロジェクトに差し替え\u003c/li\u003e\n\u003cli data-sourcepos=\"225:1-225:72\"\u003e\n\u003ccode\u003enpx @goqoo/trunks init\u003c/code\u003e で \u003ccode\u003etrunks.config.ts\u003c/code\u003e を対話的に作成\u003c/li\u003e\n\u003cli data-sourcepos=\"226:1-226:73\"\u003e\n\u003ccode\u003e.env\u003c/code\u003e または \u003ccode\u003e~/.netrc(.gpg)\u003c/code\u003e に kintone の認証情報を記入\u003c/li\u003e\n\u003cli data-sourcepos=\"227:1-227:115\"\u003e\n\u003ccode\u003enpx @goqoo/trunks\u003c/code\u003e でフィールド型定義を生成、\u003ccode\u003enpx ginue pull development\u003c/code\u003e で設定を取り込み\u003c/li\u003e\n\u003cli data-sourcepos=\"228:1-229:0\"\u003e\n\u003ccode\u003esrc/apps/sample1/\u003c/code\u003e（共通ヘルパ + 複数機能ファイル）か \u003ccode\u003esrc/apps/sample2/\u003c/code\u003e（1 ファイル完結）の好きな方をコピーして自プロジェクトのアプリ用ディレクトリを作る\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp data-sourcepos=\"230:1-230:267\"\u003e詳細な手順やディレクトリ構成、新規アプリ追加の流れは \u003ca href=\"https://github.com/goqoo-on-kintone/mr-satan/blob/main/README.md\" rel=\"nofollow noopener\" target=\"_blank\"\u003eREADME.md\u003c/a\u003e / \u003ca href=\"https://github.com/goqoo-on-kintone/mr-satan/blob/main/CLAUDE.md\" rel=\"nofollow noopener\" target=\"_blank\"\u003eCLAUDE.md\u003c/a\u003e を参照してください。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"232:1-232:55\"\u003e\n\u003cspan id=\"アプリ設計情報も-git-で管理するginue\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%A2%E3%83%97%E3%83%AA%E8%A8%AD%E8%A8%88%E6%83%85%E5%A0%B1%E3%82%82-git-%E3%81%A7%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8Bginue\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eアプリ設計情報も Git で管理する：ginue\u003c/h2\u003e\n\u003cp data-sourcepos=\"234:1-234:156\"\u003e使い方の step 6 に \u003ccode\u003enpx ginue pull\u003c/code\u003e が登場しましたが、これも拙作のツール \u003ca href=\"https://github.com/goqoo-on-kintone/ginue\" rel=\"nofollow noopener\" target=\"_blank\"\u003eginue\u003c/a\u003e です。\u003c/p\u003e\n\u003cp data-sourcepos=\"236:1-236:412\"\u003ekintone のカスタマイズ開発では、JavaScript のコードだけでなく、アプリのフィールド定義・フォームレイアウト・プロセス管理・アクセス権などの設定を触る場面も多々あります。これらをローカルに JSON として保存して Git で追跡し、開発環境と本番環境の差分管理・デプロイを行うのに ginue を使います。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"238:1-247:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c\"\u003e# 開発環境からアプリ設定を pull\u003c/span\u003e\nnpx ginue pull development\n\n\u003cspan class=\"c\"\u003e# 特定アプリのみ\u003c/span\u003e\nnpx ginue pull development \u003cspan class=\"nt\"\u003e-A\u003c/span\u003e sample1\n\n\u003cspan class=\"c\"\u003e# 開発環境から本番環境へ push\u003c/span\u003e\nnpx ginue push development:production \u003cspan class=\"nt\"\u003e-A\u003c/span\u003e sample1\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"249:1-249:442\"\u003eテンプレートでは \u003ccode\u003ekintone-settings/development/\u003c/code\u003e / \u003ccode\u003ekintone-settings/production/\u003c/code\u003e 配下にファイルが吐き出され、「アプリ設定の変更を PR にしてレビュー → 開発環境で検証 → 本番環境へ push」という流れをコードベースから一元的に扱えるようになります。\u003ccode\u003e.ginuerc.js\u003c/code\u003e に環境ごとのドメインとアプリ ID を書いておくだけで使い始められます。\u003c/p\u003e\n\u003cp data-sourcepos=\"251:1-251:313\"\u003e\u003ccode\u003e@goqoo/trunks\u003c/code\u003e が「コード側の型」を kintone から引っ張ってくる役割だとすれば、ginue は「アプリ設定そのもの」を kintone と同期する役割。両者を組み合わせることで、\u003cstrong\u003eコードもアプリ設計も丸ごと Git で扱える\u003c/strong\u003e開発体制になります。\u003c/p\u003e\n\u003cp data-sourcepos=\"253:1-253:181\"\u003e手前味噌ですが、個人的には\u003cstrong\u003eginue なしでは kintone 開発がまともに回せない\u003c/strong\u003eくらい、どの案件でも必ず手元に置いているツールです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"255:1-255:12\"\u003e\n\u003cspan id=\"まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまとめ\u003c/h2\u003e\n\u003cul data-sourcepos=\"257:1-262:0\"\u003e\n\u003cli data-sourcepos=\"257:1-257:105\"\u003ekintone カスタマイズは「webpack でフルビルド」と「素の JS」の二択になりがち\u003c/li\u003e\n\u003cli data-sourcepos=\"258:1-258:118\"\u003e中間案として「\u003ccode\u003e.js\u003c/code\u003e をそのまま上げる、ただし \u003ccode\u003etypes.ts\u003c/code\u003e + JSDoc で型は効かせる」がある\u003c/li\u003e\n\u003cli data-sourcepos=\"259:1-259:145\"\u003eこのスタイルは JSDoc メンテコストで人間単独だと続きにくかったが、生成 AI 時代になって現実的になった\u003c/li\u003e\n\u003cli data-sourcepos=\"260:1-260:148\"\u003eコード側は \u003ccode\u003e@goqoo/trunks\u003c/code\u003e で型生成、アプリ設計側は \u003ccode\u003eginue\u003c/code\u003e で管理、とツールを組み合わせて丸ごと追跡できる\u003c/li\u003e\n\u003cli data-sourcepos=\"261:1-262:0\"\u003eMr. Satan はそのためのテンプレート。Claude Code 等と併用する前提で使えます\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"263:1-263:220\"\u003e本格開発なら \u003ca href=\"https://github.com/goqoo-on-kintone/goqoo\" rel=\"nofollow noopener\" target=\"_blank\"\u003eGoqoo\u003c/a\u003e、軽量で編集余地を残したいなら \u003ca href=\"https://github.com/goqoo-on-kintone/mr-satan\" rel=\"nofollow noopener\" target=\"_blank\"\u003eSatan\u003c/a\u003e、と使い分けてもらえれば幸いです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"265:1-265:48\"\u003e\n\u003cspan id=\"最後にひとつ叫ばせてください\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%9C%80%E5%BE%8C%E3%81%AB%E3%81%B2%E3%81%A8%E3%81%A4%E5%8F%AB%E3%81%B0%E3%81%9B%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e最後にひとつ、叫ばせてください\u003c/h2\u003e\n\u003cp data-sourcepos=\"267:1-267:521\"\u003eちょっと別の話なんですけどねぇ、kintoneカスタマイズのベストプラクティスに沿って、このテンプレートの \u003ccode\u003e.js\u003c/code\u003e もすべて \u003ccode\u003e{ ... }\u003c/code\u003e の IIFE ブロックで囲んでいたり、共通ユーティリティを \u003ccode\u003ewindow.__xxxCommon\u003c/code\u003e というブラ下げ方式で公開していたりするわけですけど、、、\u003cstrong\u003ekintone のカスタマイズ JS を \u003ccode\u003etype=\"module\"\u003c/code\u003e として読み込む方法がない\u003c/strong\u003eから未だにこんな書き方しなきゃいけないんですよ。\u003c/p\u003e\n\u003cp data-sourcepos=\"269:1-269:49\"\u003e素直に ES モジュールが使えるなら、\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"271:1-274:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// こう書きたい\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nx\"\u003ehasValue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003etoday\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003efrom\u003c/span\u003e \u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e./common.js\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"276:1-276:137\"\u003eで済むところを、今は window オブジェクトの片隅に値をぶら下げる昔ながらの作法でしのいでいます。\u003c/p\u003e\n\u003cp data-sourcepos=\"278:1-278:615\"\u003eちなみにこの \u003ccode\u003ewindow.__xxx\u003c/code\u003e 周りの管理（\u003ccode\u003ecommon.js\u003c/code\u003e への追加と \u003ccode\u003eWindow\u003c/code\u003e インターフェース拡張の同期、ファイル読み込み順の維持など）も、前述の JSDoc メンテと同じく \u003cstrong\u003e人手だと地味に辛いけれど生成 AI は平気でこなしてくれる\u003c/strong\u003e 系の作業です。Mr. Satan がまともな開発体験として成立するのは、型安全に限らずこうした雑務まで AI が裏で引き受けてくれているから、という側面がかなり大きい。とはいえ、そもそも要らないなら無いに越したことはないので、\u003c/p\u003e\n\u003cp data-sourcepos=\"280:1-280:314\"\u003e\u003cstrong\u003eサイボウズさん、早く kintone カスタマイズで \u003ccode\u003etype=\"module\"\u003c/code\u003e の JavaScript が適用できるようにしてください！\u003c/strong\u003e そうなれば IIFE と \u003ccode\u003ewindow.__xxx\u003c/code\u003e 一式は一掃できて、もっと普通の JavaScript として書けるようになります。切実にお願いします。\u003c/p\u003e\n","body":"kintone のカスタマイズ開発を「**ビルドは挟まない、でもエディタ上では型補完と型チェックが効く**」状態で進めるためのテンプレートリポジトリ [Mr. Satan](https://github.com/goqoo-on-kintone/mr-satan) を公開しました。GitHub の「Use this template」からそのまま派生リポジトリを作って使えます。\n\n本記事ではこのテンプレートの位置づけと、核となる「`.js` から `types.ts` を JSDoc で参照する」パターンを具体例で解説します。\n\n## kintone カスタマイズの現実：2 つの極端\n\nkintone のカスタマイズ開発には、大きく分けて 2 つの方向性があります。\n\n### 1. webpack などでバンドルしてアップロード\n\nTypeScript・最新 JS 構文・npm エコシステムをフル活用できる反面、kintone にアップロードされるのはバンドル後の成果物。そのコードを直接編集することは事実上不可能で、開発環境を持っている担当者でないと手を入れられません。拙作 [Goqoo on kintone](https://github.com/goqoo-on-kintone/goqoo) はこの方向性の代表例です。\n\n本格開発には最適ですが、「定数を一文字書き換えたい」だけでも再ビルド・再アップロードが必要になります。\n\n### 2. 素の `.js` をそのままアップロード\n\nkintone 上で直接編集できるので手軽ですが、型補完・型チェック・モジュール分割といったモダンな開発体験は諦めることになります。フィールド名をタイポしてもエディタは何も教えてくれません。\n\n---\n\nどちらも一長一短で、「納品後に顧客側で定数を差し替えてほしい」「保守契約なしで納品完結する案件」のようなシチュエーションでは、前者は過剰で、後者は辛い、という状態が続いていました。\n\n## 3 つ目の選択肢：型は書く、ただしビルドはしない\n\nMr. Satan はその中間を狙ったテンプレートです。\n\n- `.js` をビルドせず**そのまま kintone にアップロード** → kintone 上で直接編集できる余地を残す\n- 開発中は `types.ts` に型定義を書き、`.js` からは **JSDoc の `@type {import('./types').Foo}`** で参照 → VS Code 上では型補完・型チェックが効く\n- ビルド工程がないので「ソースと本番の同期ズレ」が原理的に起きない\n- npmでのscaffoldはあえて採用せず、戦闘力低めのGitHubテンプレートに留めた\n\n以降、この仕組みのコアとなる `types.ts` + JSDoc 参照を具体例で見ていきます。\n\n## 具体例：`.js` から `types.ts` を JSDoc で参照する\n\nテンプレートに同梱されているサンプルアプリ（`src/apps/sample1/`）を題材に、フィールド型定義から JSDoc 参照までの流れを追います。\n\n### Step 1: trunks でフィールド型を生成する\n\nkintone のアプリからフィールド型定義を自動生成するのに、拙作 [`@goqoo/trunks`](https://github.com/goqoo-on-kintone/trunks) を使います。`@kintone/dts-gen` のラッパーで、`trunks.config.ts` に複数アプリを登録しておくと一発で全アプリの型を出力できます。\n\ntrunks 自体について詳しくは別記事 [@kintone/dts-gen を複数アプリで一括実行するラッパーツール @goqoo/trunks を作った](https://qiita.com/the_red/items/3ae726a7eed2d03dc794) を参照してください。\n\n```typescript\n// trunks.config.ts\nimport { defineConfig } from '@goqoo/trunks';\n\nexport default defineConfig({\n  host: 'your-subdomain.cybozu.com',\n  apps: {\n    sample1: 1,\n  },\n  auth: { type: 'password' },\n});\n```\n\n`npx @goqoo/trunks` を実行すると `dts/sample1-fields.d.ts` が生成されます。\n\n```typescript\n// dts/sample1-fields.d.ts（抜粋）\ndeclare namespace kintone.types {\n  interface Sample1Fields {\n    件名: kintone.fieldTypes.SingleLineText;\n    本文: kintone.fieldTypes.MultiLineText;\n    担当者: kintone.fieldTypes.UserSelect;\n    期日: kintone.fieldTypes.Date;\n  }\n  interface SavedSample1Fields extends Sample1Fields {\n    $id: kintone.fieldTypes.Id;\n    $revision: kintone.fieldTypes.Revision;\n    // ... システムフィールド一式\n  }\n}\n```\n\nここで生成されるのは **kintone 側のフィールド定義そのもの**。日本語のフィールド名もそのまま型になります。\n\n### Step 2: `types.ts` でイベント型を組み立てる\n\nkintone のイベント型は 2 層に分けて管理します。汎用的な部分（kintone 側の共通構造）は **全アプリ共通の `src/types.ts`** に一度だけ書き、**各アプリの `src/apps/{app}/types.ts`** はそこから `import type` で引き込んでアプリ固有のレコード型を食わせるだけ、という二段構え。\n\nまず汎用側:\n\n```typescript\n// src/types.ts\nexport type KintoneEvent = {\n  appId: number;\n  type: string;\n  error?: string;\n};\n\nexport type IndexEvent\u003cT\u003e = KintoneEvent \u0026 {\n  records: T[];\n  viewType: 'list' | 'calendar' | 'custom';\n  viewId: number;\n  viewName: string;\n  offset: number | null;\n  size: number | null;\n  date: string | null;\n};\n\nexport type DetailEvent\u003cT\u003e = KintoneEvent \u0026 {\n  record: T;\n  recordId: number;\n  reuse?: boolean;\n};\n\nexport type SubmitEvent\u003cT\u003e = KintoneEvent \u0026 {\n  record: T;\n  changes?: {\n    field: { type: string; value: unknown };\n    row?: { id: string; value: Record\u003cstring, unknown\u003e };\n  };\n};\n```\n\n次にアプリ固有側:\n\n```typescript\n// src/apps/sample1/types.ts\nimport type { IndexEvent, DetailEvent, SubmitEvent } from '../../types';\n\n// Step 1 で生成された型を流用\nexport type Sample1Record = kintone.types.SavedSample1Fields;\n\n// イベント型はレコード型を食わせるだけ\nexport type Sample1IndexEvent = IndexEvent\u003cSample1Record\u003e;\nexport type Sample1DetailEvent = DetailEvent\u003cSample1Record\u003e;\nexport type Sample1SubmitEvent = SubmitEvent\u003cSample1Record\u003e;\n```\n\nアプリの `types.ts` が薄く保てるのがポイント。アプリが 10 個あっても、kintone のイベント構造の定義は `src/types.ts` に一度書けば使い回せます。新規アプリを追加するときも、アプリ側に書くのは「レコード型を食わせたイベント型のエイリアス」だけで済みます。\n\n### Step 3: `.js` から JSDoc で `types.ts` を参照する\n\nここが本題です。実装用の `.js` 側では、ファイル先頭に `//@ts-check` を付けた上で、イベントハンドラの引数に JSDoc で型を与えます。\n\n以下の例は `edit-show.js` の抜粋。前提として sample1 には `common.js` を 1 本置いてあり、同じアプリ内の複数ファイルから使い回したいユーティリティ（ここでは `hasValue`）を `window.__sample1Common` 経由で公開しています。`edit-show.js` はその `__sample1Common` から `hasValue` を取り出して使います。\n\n```javascript\n//@ts-check\n// src/apps/sample1/edit-show.js\n{\n  const { hasValue } = window.__sample1Common;\n\n  kintone.events.on(\n    ['app.record.create.show', 'app.record.edit.show'],\n    (/** @type {import('./types').Sample1DetailEvent} */ event) =\u003e {\n      const { record } = event;\n\n      // 件名（SingleLineText）の value にアクセス — IDE で補完が効く\n      if (hasValue(record.件名)) {\n        record.本文.disabled = true;\n      }\n\n      // 期日（Date）が空なら今日の日付を入れる\n      if (!hasValue(record.期日)) {\n        record.期日.value = luxon.DateTime.now().toFormat('yyyy-MM-dd');\n      }\n\n      return event;\n    },\n  );\n}\n```\n\nポイントは `(/** @type {import('./types').Sample1DetailEvent} */ event) =\u003e` の部分。JSDoc の `@type` で `types.ts` から `Sample1DetailEvent` を import することで、それ以降 `event.record.件名.value` のような形で**型補完とタイポチェックがフルに効きます**。\n\n実ファイルはあくまで素の `.js` なので、そのまま kintone にアップロードできます。ビルド成果物ではないので、アップロード後に kintone 側で直接編集して定数をいじる、といった運用も可能です。\n\n`sample1/` アプリは `common.js` / `edit-show.js` / `index-show.js` の 3 本構成で、これらを同じ kintone アプリの「JavaScript / CSS でカスタマイズ」に登録して使います。`common.js` は後続ファイルから参照している都合上、先頭に並べてください。この点は kintone カスタマイズ界隈で普通に行われている方法ですね。\n\nもう一つの `sample2/` アプリは `edit-submit.js` だけで完結する最小構成になっています。共通ヘルパを切り出す必要がない規模のアプリでは `common.js` は省略して構いません。\n\nさらに、複数アプリ横断で使いたいユーティリティのために `src/global.js` という全アプリ共通 JS も同梱しています。kintoneシステム管理の「JavaScript / CSSでカスタマイズ」で登録すると、どのアプリの JS からも `window.__global` で参照できます。ヘルパの置き場所は以下の 3 階層で使い分けるイメージです。\n\n| スコープ | 置き場所 | 参照 | 例 |\n|---------|---------|------|-----|\n| 全アプリ横断 | `src/global.js` | `window.__global` | ログ関数 `log(tag, ...)` |\n| アプリ内共通 | `src/apps/{app}/common.js` | `window.__{app}Common` | sample1 の `hasValue` / `today` |\n| ファイル内ローカル | IIFE ブロック内 | 直接参照 | sample2 の `isValidEmail` |\n\n### 比較：全部インラインの JSDoc で書くと？\n\n`types.ts` + `import` 方式には、「インラインで JSDoc にオブジェクト型リテラルを直接書く」という代替があります。ただしその方式は現実的に辛いです。\n\n```javascript\n// 悪い例：インラインで全部書こうとした場合\nkintone.events.on(\n  ['app.record.edit.show'],\n  /** @param {{ appId: number, record: { 件名: { type: 'SINGLE_LINE_TEXT', value: string }, 本文: { type: 'MULTI_LINE_TEXT', value: string, disabled?: boolean }, 期日: { type: 'DATE', value: string } /* ... */ }, recordId: number, type: string }} event */\n  (event) =\u003e { ... }\n);\n```\n\nこの書き方の問題点:\n\n- **一行が暴発する**。フィールド数が増えると JSDoc コメントだけで画面が埋まる\n- **他のイベント（`submit`、`index.show` など）でも同じ型を書き直す羽目になる**\n- **フィールド定義が変わったらすべての JSDoc を手で直さなければならない**\n\n一方、`types.ts` に一度だけ定義を書く方式なら、JSDoc 側は `import('./types').Sample1DetailEvent` という 1 行の参照だけで済みます。`types.ts` を一箇所直せば、それを import している全 `.js` に自動的に波及します。\n\n**TS で書ける部分は TS で、JSDoc は参照だけ**。これがこのスタイルの肝です。\n\n## なぜ今このスタイルが現実的になったのか\n\n実は `.js` + JSDoc + `types.ts` という構成自体は何年も前に思いついていて、Goqoo on kintoneの設定ファイル [goqoo.config.js](https://github.com/goqoo-on-kintone/goqoo-templates/blob/5da0fda31b3f34eabd70740580de60dd3badd7ad/templates/default/goqoo.config.js) / [goqoo.config.types.ts](https://github.com/goqoo-on-kintone/goqoo-templates/blob/5da0fda31b3f34eabd70740580de60dd3badd7ad/templates/default/goqoo.config.types.ts) でもこのパターンを採用しています。\n\nしかし、ロジックを書くJSにこのパターンを適用しようとすると今まではうまく行きませんでした。シンプルな設定ファイルに比べると、変数・関数に細かく型を当てていく作業が沢山あるし、型の作りが特殊になるケースもそれなりに出てきます。\n\n`@type {import('./types').Foo}` の付け直しや、`types.ts` 側の変更への追従といった**JSDoc のメンテナンスは、人手でやると地味に頭を使う作業**です。「この JSDoc は正しく解決されているか？」「import パスは合っているか？」と確認していく途中で気持ちが折れて、結局は「全部 TypeScript にして webpack でビルドするわ！インラインで型が書けるのサイコー！」と結論づくことばかりでした。\n\n**Claude Code をはじめとする生成 AI は、この種の機械的な追従作業を苦にしません**。むしろ得意分野です。JSDoc メンテのコスト問題が AI 側に吸収されるので、人間は「どのような型を `types.ts` に置くか」という本質的な設計だけに集中できます。\n\nこのテンプレートを公開するに至った動機の一つが、まさにここにあります。以前何度か諦めたこのパターンが、AIのお陰でようやく実案件でも採用できるようになりました。そんな経緯があるので、**Mr. Satanは生成 AI と協働する前提**で使うことを推奨します（もちろん人手だけでも動作します）。\n\nリポジトリには AI 向けのガイドとして [CLAUDE.md](https://github.com/goqoo-on-kintone/mr-satan/blob/main/CLAUDE.md) を同梱してあり、Claude Code から参照される前提で規約・命名・落とし穴（`common.js` の読み込み順、`Window` インターフェース拡張パターン、kintone API を推測で書かない、など）を整理しています。\n\n## 使い方\n\n1. GitHub の「**Use this template**」ボタンから自分のリポジトリを作る\n2. `npm install`\n3. `.ginuerc.js` のドメインと `appId` を実プロジェクトに差し替え\n4. `npx @goqoo/trunks init` で `trunks.config.ts` を対話的に作成\n5. `.env` または `~/.netrc(.gpg)` に kintone の認証情報を記入\n6. `npx @goqoo/trunks` でフィールド型定義を生成、`npx ginue pull development` で設定を取り込み\n7. `src/apps/sample1/`（共通ヘルパ + 複数機能ファイル）か `src/apps/sample2/`（1 ファイル完結）の好きな方をコピーして自プロジェクトのアプリ用ディレクトリを作る\n\n詳細な手順やディレクトリ構成、新規アプリ追加の流れは [README.md](https://github.com/goqoo-on-kintone/mr-satan/blob/main/README.md) / [CLAUDE.md](https://github.com/goqoo-on-kintone/mr-satan/blob/main/CLAUDE.md) を参照してください。\n\n## アプリ設計情報も Git で管理する：ginue\n\n使い方の step 6 に `npx ginue pull` が登場しましたが、これも拙作のツール [ginue](https://github.com/goqoo-on-kintone/ginue) です。\n\nkintone のカスタマイズ開発では、JavaScript のコードだけでなく、アプリのフィールド定義・フォームレイアウト・プロセス管理・アクセス権などの設定を触る場面も多々あります。これらをローカルに JSON として保存して Git で追跡し、開発環境と本番環境の差分管理・デプロイを行うのに ginue を使います。\n\n```bash\n# 開発環境からアプリ設定を pull\nnpx ginue pull development\n\n# 特定アプリのみ\nnpx ginue pull development -A sample1\n\n# 開発環境から本番環境へ push\nnpx ginue push development:production -A sample1\n```\n\nテンプレートでは `kintone-settings/development/` / `kintone-settings/production/` 配下にファイルが吐き出され、「アプリ設定の変更を PR にしてレビュー → 開発環境で検証 → 本番環境へ push」という流れをコードベースから一元的に扱えるようになります。`.ginuerc.js` に環境ごとのドメインとアプリ ID を書いておくだけで使い始められます。\n\n`@goqoo/trunks` が「コード側の型」を kintone から引っ張ってくる役割だとすれば、ginue は「アプリ設定そのもの」を kintone と同期する役割。両者を組み合わせることで、**コードもアプリ設計も丸ごと Git で扱える**開発体制になります。\n\n手前味噌ですが、個人的には**ginue なしでは kintone 開発がまともに回せない**くらい、どの案件でも必ず手元に置いているツールです。\n\n## まとめ\n\n- kintone カスタマイズは「webpack でフルビルド」と「素の JS」の二択になりがち\n- 中間案として「`.js` をそのまま上げる、ただし `types.ts` + JSDoc で型は効かせる」がある\n- このスタイルは JSDoc メンテコストで人間単独だと続きにくかったが、生成 AI 時代になって現実的になった\n- コード側は `@goqoo/trunks` で型生成、アプリ設計側は `ginue` で管理、とツールを組み合わせて丸ごと追跡できる\n- Mr. Satan はそのためのテンプレート。Claude Code 等と併用する前提で使えます\n\n本格開発なら [Goqoo](https://github.com/goqoo-on-kintone/goqoo)、軽量で編集余地を残したいなら [Satan](https://github.com/goqoo-on-kintone/mr-satan)、と使い分けてもらえれば幸いです。 \n\n## 最後にひとつ、叫ばせてください\n\nちょっと別の話なんですけどねぇ、kintoneカスタマイズのベストプラクティスに沿って、このテンプレートの `.js` もすべて `{ ... }` の IIFE ブロックで囲んでいたり、共通ユーティリティを `window.__xxxCommon` というブラ下げ方式で公開していたりするわけですけど、、、**kintone のカスタマイズ JS を `type=\"module\"` として読み込む方法がない**から未だにこんな書き方しなきゃいけないんですよ。\n\n素直に ES モジュールが使えるなら、\n\n```javascript\n// こう書きたい\nimport { hasValue, today } from './common.js';\n```\n\nで済むところを、今は window オブジェクトの片隅に値をぶら下げる昔ながらの作法でしのいでいます。\n\nちなみにこの `window.__xxx` 周りの管理（`common.js` への追加と `Window` インターフェース拡張の同期、ファイル読み込み順の維持など）も、前述の JSDoc メンテと同じく **人手だと地味に辛いけれど生成 AI は平気でこなしてくれる** 系の作業です。Mr. Satan がまともな開発体験として成立するのは、型安全に限らずこうした雑務まで AI が裏で引き受けてくれているから、という側面がかなり大きい。とはいえ、そもそも要らないなら無いに越したことはないので、\n\n**サイボウズさん、早く kintone カスタマイズで `type=\"module\"` の JavaScript が適用できるようにしてください！** そうなれば IIFE と `window.__xxx` 一式は一掃できて、もっと普通の JavaScript として書けるようになります。切実にお願いします。\n","coediting":false,"comments_count":0,"created_at":"2026-04-22T01:45:41+09:00","group":null,"id":"05a7708a2b3cb08b99d7","likes_count":3,"private":false,"reactions_count":0,"stocks_count":2,"tags":[{"name":"TypeScript","versions":[]},{"name":"JSDoc","versions":[]},{"name":"kintone","versions":[]},{"name":"生成AI","versions":[]},{"name":"ClaudeCode","versions":[]}],"title":"kintone カスタマイズを「ビルドせず型安全に」書くためのテンプレート Mr. Satan を公開した","updated_at":"2026-04-22T02:46:29+09:00","url":"https://qiita.com/the_red/items/05a7708a2b3cb08b99d7","user":{"description":"富山県の旧細入村でリモートワークしてるプログラマー 。\r\nkintoneカスタマイズ用のOSSフレームワーク「Goqoo on kintone」シリーズを開発しています。 https://github.com/goqoo-on-kintone","facebook_id":"hisaki.akaza","followees_count":95,"followers_count":77,"github_login_name":"the-red","id":"the_red","items_count":83,"linkedin_id":"","location":"Toyama, Japan","name":"赤座 久樹","organization":"","permanent_id":24333,"profile_image_url":"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24333/profile-images/1699946685","team_only":false,"twitter_screen_name":null,"website_url":""},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-2:110\"\u003ekintone の重複レコード問題、困っていませんか？\u003cbr\u003e\nkintone で会社マスタや人物マスタを運用していると、こんな状況になりがちです。\u003c/p\u003e\n\u003cp data-sourcepos=\"4:1-7:126\"\u003e担当者が同じ会社を別々に登録してしまった\u003cbr\u003e\nCSV インポート時に既存データと重複した\u003cbr\u003e\n表記ゆれ（「株式会社〇〇」と「㈱〇〇」など）で別レコードになっている\u003cbr\u003e\n件数が少ないうちは手動で対応できますが、数十件・数百件になると現実的ではありません。\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-10:99\"\u003e手動対応の何が大変か\u003cbr\u003e\n重複レコードを手動でマージしようとすると、以下の作業が発生します。\u003c/p\u003e\n\u003cp data-sourcepos=\"12:1-16:174\"\u003eどちらのレコードを残すか判断する\u003cbr\u003e\n残すレコードに必要な情報をコピーする\u003cbr\u003e\n関連アプリ（案件・活動履歴など）の参照先を付け替える ← これが一番大変\u003cbr\u003e\n不要なレコードを削除する\u003cbr\u003e\n特に 3 番が厄介で、関連アプリが多いほど修正箇所が増えます。ルックアップフィールドで参照している場合はさらに複雑です。\u003c/p\u003e\n\u003cp data-sourcepos=\"18:1-19:110\"\u003eマスタデータマージ プラグインで解決\u003cbr\u003e\nマスタデータマージ プラグイン を使うと、これらの作業をほぼ自動化できます。\u003c/p\u003e\n\u003cp data-sourcepos=\"21:1-22:37\"\u003e主な機能\u003cbr\u003e\n① 重複レコードの一括検出\u003c/p\u003e\n\u003cp data-sourcepos=\"24:1-24:223\"\u003e名前・電話番号・メールアドレスなど複数のフィールドを組み合わせて重複候補を自動検出します。ボタン1つで一覧表示されるので、目視で探す必要がありません。\u003c/p\u003e\n\u003cp data-sourcepos=\"26:1-26:47\"\u003e② 2レコードを並べて比較・マージ\u003c/p\u003e\n\u003cp data-sourcepos=\"28:1-28:163\"\u003e重複候補を2つ並べて表示し、フィールドごとにどちらの値を残すか選択できます。確認しながら安全にマージできます。\u003c/p\u003e\n\u003cp data-sourcepos=\"30:1-30:46\"\u003e③ 関連アプリの参照先を自動更新\u003c/p\u003e\n\u003cp data-sourcepos=\"32:1-32:228\"\u003e案件アプリ・活動履歴アプリなど、削除するレコードを参照していた関連アプリのデータを、存続レコードへ自動で付け替えます。手動での修正作業が不要になります。\u003c/p\u003e\n\u003cp data-sourcepos=\"34:1-34:28\"\u003e④ 独自コードに対応\u003c/p\u003e\n\u003cp data-sourcepos=\"36:1-36:180\"\u003eレコード番号だけでなく、独自に設定したコードフィールド（会社コード・人物コードなど）を使った参照関係にも対応しています。\u003c/p\u003e\n\u003cp data-sourcepos=\"38:1-38:46\"\u003e⑤ ルックアップフィールドに対応\u003c/p\u003e\n\u003cp data-sourcepos=\"40:1-40:138\"\u003eルックアップフィールドで参照しているレコードも、マージ時に存続レコードへ自動で付け替えます。\u003c/p\u003e\n\u003cp data-sourcepos=\"42:1-45:60\"\u003e■こんな方におすすめ\u003cbr\u003e\nkintone で会社マスタ・人物マスタ・顧客マスタを管理している\u003cbr\u003e\n重複データの整理・名寄せ作業を効率化したい\u003cbr\u003e\n関連アプリが多くて手動での付け替えが大変\u003c/p\u003e\n\u003cp data-sourcepos=\"47:1-51:96\"\u003e■料金\u003cbr\u003e\nプラン\t料金\u003cbr\u003e\n月額プラン\t 14日間無料トライアル後、3,300円（税込）/ 月\u003cbr\u003e\n買い切りプラン\t330,000円（税込）\u003cbr\u003e\n月額プランはいつでも解約可能。まず試してみたい方におすすめです。\u003c/p\u003e\n\u003cp data-sourcepos=\"53:1-53:72\"\u003eマニュアルは購入前に無料でダウンロードできます。\u003c/p\u003e\n\u003cp data-sourcepos=\"55:1-55:47\"\u003e👉 \u003ca href=\"https://fsm-works.com/plugins/master-merge\" class=\"autolink\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://fsm-works.com/plugins/master-merge\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"57:1-60:122\"\u003eまとめ\u003cbr\u003e\nkintone の重複レコード問題は放置すると業務データの信頼性が下がります。マスタデータマージ プラグインを使えば、重複検出からマージ・関連アプリの更新まで一括で対応できます。\u003cbr\u003e\n名寄せ作業に時間をとられている方はぜひ試してみてください。\u003cbr\u003e\n月額プランは14日間無料で試せるので、まずは自社データで動作を確認してみてください。\u003c/p\u003e\n","body":"kintone の重複レコード問題、困っていませんか？\nkintone で会社マスタや人物マスタを運用していると、こんな状況になりがちです。\n\n担当者が同じ会社を別々に登録してしまった\nCSV インポート時に既存データと重複した\n表記ゆれ（「株式会社〇〇」と「㈱〇〇」など）で別レコードになっている\n件数が少ないうちは手動で対応できますが、数十件・数百件になると現実的ではありません。\n\n手動対応の何が大変か\n重複レコードを手動でマージしようとすると、以下の作業が発生します。\n\nどちらのレコードを残すか判断する\n残すレコードに必要な情報をコピーする\n関連アプリ（案件・活動履歴など）の参照先を付け替える ← これが一番大変\n不要なレコードを削除する\n特に 3 番が厄介で、関連アプリが多いほど修正箇所が増えます。ルックアップフィールドで参照している場合はさらに複雑です。\n\nマスタデータマージ プラグインで解決\nマスタデータマージ プラグイン を使うと、これらの作業をほぼ自動化できます。\n\n主な機能\n① 重複レコードの一括検出\n\n名前・電話番号・メールアドレスなど複数のフィールドを組み合わせて重複候補を自動検出します。ボタン1つで一覧表示されるので、目視で探す必要がありません。\n\n② 2レコードを並べて比較・マージ\n\n重複候補を2つ並べて表示し、フィールドごとにどちらの値を残すか選択できます。確認しながら安全にマージできます。\n\n③ 関連アプリの参照先を自動更新\n\n案件アプリ・活動履歴アプリなど、削除するレコードを参照していた関連アプリのデータを、存続レコードへ自動で付け替えます。手動での修正作業が不要になります。\n\n④ 独自コードに対応\n\nレコード番号だけでなく、独自に設定したコードフィールド（会社コード・人物コードなど）を使った参照関係にも対応しています。\n\n⑤ ルックアップフィールドに対応\n\nルックアップフィールドで参照しているレコードも、マージ時に存続レコードへ自動で付け替えます。\n\n■こんな方におすすめ\nkintone で会社マスタ・人物マスタ・顧客マスタを管理している\n重複データの整理・名寄せ作業を効率化したい\n関連アプリが多くて手動での付け替えが大変\n\n■料金\nプラン\t料金\n月額プラン\t 14日間無料トライアル後、3,300円（税込）/ 月\n買い切りプラン\t330,000円（税込）\n月額プランはいつでも解約可能。まず試してみたい方におすすめです。\n\nマニュアルは購入前に無料でダウンロードできます。\n\n👉 https://fsm-works.com/plugins/master-merge\n\nまとめ\nkintone の重複レコード問題は放置すると業務データの信頼性が下がります。マスタデータマージ プラグインを使えば、重複検出からマージ・関連アプリの更新まで一括で対応できます。\n名寄せ作業に時間をとられている方はぜひ試してみてください。\n月額プランは14日間無料で試せるので、まずは自社データで動作を確認してみてください。\n","coediting":false,"comments_count":0,"created_at":"2026-04-20T17:36:52+09:00","group":null,"id":"941d2eaa26033122903f","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"名寄せ","versions":[]},{"name":"マスタデータ","versions":[]},{"name":"業務効率化","versions":[]},{"name":"マージ","versions":[]}],"title":"kintone の重複レコードを自動マージする方法【プラグイン紹介】","updated_at":"2026-04-21T17:39:35+09:00","url":"https://qiita.com/fsmworks2026-svg/items/941d2eaa26033122903f","user":{"description":null,"facebook_id":null,"followees_count":1,"followers_count":0,"github_login_name":"fsmworks2026-svg","id":"fsmworks2026-svg","items_count":1,"linkedin_id":null,"location":null,"name":"","organization":null,"permanent_id":4412215,"profile_image_url":"https://avatars.githubusercontent.com/u/277015128?v=4","team_only":false,"twitter_screen_name":null,"website_url":null},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:162\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F4405830%2Fceddfbb6-d6c8-467c-ab47-47ae5346ccd0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=2de97bf6daec9ebe53e3eebe5f337434\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F4405830%2Fceddfbb6-d6c8-467c-ab47-47ae5346ccd0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=2de97bf6daec9ebe53e3eebe5f337434\" alt=\"スクリーンショット 2026-04-14 091807.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F4405830%2Fceddfbb6-d6c8-467c-ab47-47ae5346ccd0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=e8f57f175d46ecbe4be72729a03d15ad 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4405830/ceddfbb6-d6c8-467c-ab47-47ae5346ccd0.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"4:1-5:83\"\u003e「kintoneにデータは溜まっているけど、うまく活用できていない」\u003cbr\u003e\n「AIツールとの連携って、どうやって始めればいいんだろう」\u003c/p\u003e\n\u003cp data-sourcepos=\"7:1-7:311\"\u003e社内でkintoneを運用している情報システム担当者の方なら、こうした悩みを一度は感じたことがあるのではないでしょうか。私自身、kintoneの市民開発を推進する立場として、日々増え続けるアプリの品質管理に頭を抱えていました。\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-9:388\"\u003eそんな中、Difyの公式kintoneコネクタが実装されたことをきっかけに、実際にAIを活用したアプリ設定の自動レビューシステムを開発してみました。この記事では、その過程で得られた技術的な知見と、運用上の壁、そして今後の可能性について、実務担当者の視点から詳しくお伝えします。\u003c/p\u003e\n\u003ch5 data-sourcepos=\"11:1-11:154\"\u003e\n\u003cspan id=\"本記事はkintoneに保存した日々の作業メモを元にdifyaiエージェントを活用して構成執筆しています\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%9C%AC%E8%A8%98%E4%BA%8B%E3%81%AFkintone%E3%81%AB%E4%BF%9D%E5%AD%98%E3%81%97%E3%81%9F%E6%97%A5%E3%80%85%E3%81%AE%E4%BD%9C%E6%A5%AD%E3%83%A1%E3%83%A2%E3%82%92%E5%85%83%E3%81%ABdifyai%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%82%92%E6%B4%BB%E7%94%A8%E3%81%97%E3%81%A6%E6%A7%8B%E6%88%90%E5%9F%B7%E7%AD%86%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e※本記事はkintoneに保存した日々の作業メモを元に、Dify（AIエージェント）を活用して構成・執筆しています。\u003c/h5\u003e\n\u003ch2 data-sourcepos=\"13:1-13:76\"\u003e\n\u003cspan id=\"kintonedify連携を検討する前に知っておくべき基礎知識\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintonedify%E9%80%A3%E6%90%BA%E3%82%92%E6%A4%9C%E8%A8%8E%E3%81%99%E3%82%8B%E5%89%8D%E3%81%AB%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8F%E3%81%B9%E3%81%8D%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone×Dify連携を検討する前に知っておくべき基礎知識\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"15:1-15:20\"\u003e\n\u003cspan id=\"difyとは何か\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#dify%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eDifyとは何か\u003c/h3\u003e\n\u003cp data-sourcepos=\"17:1-17:138\"\u003e\u003cstrong\u003eDify\u003c/strong\u003eは、LLM(大規模言語モデル)と外部ツールをノーコードで連結できるAI開発プラットフォームです。\u003c/p\u003e\n\u003cp data-sourcepos=\"19:1-19:174\"\u003e単なるチャットボット構築ツールではなく、条件分岐や繰り返し処理を伴う複雑なワークフローの自動化が可能な点が特徴です。\u003c/p\u003e\n\u003cp data-sourcepos=\"21:1-21:114\"\u003e私がDifyに注目したのは、社内でClaude、n8nなどのAI活用が活性化していた時期のこと。\u003c/p\u003e\n\u003cp data-sourcepos=\"23:1-23:235\"\u003e業界イベントでDify×kintone連携の情報を得て、すぐに検証を開始しました。従来のAPI連携と異なり、ノーコードで複雑な業務フローを構築できる可能性に魅力を感じたのです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"25:1-25:65\"\u003e\n\u003cspan id=\"kintone公式コネクタの実装で何が変わったのか\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E5%85%AC%E5%BC%8F%E3%82%B3%E3%83%8D%E3%82%AF%E3%82%BF%E3%81%AE%E5%AE%9F%E8%A3%85%E3%81%A7%E4%BD%95%E3%81%8C%E5%A4%89%E3%82%8F%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone公式コネクタの実装で何が変わったのか\u003c/h3\u003e\n\u003cp data-sourcepos=\"27:1-27:279\"\u003eDifyの公式kintoneコネクタが実装されたことで、\u003cstrong\u003eデータの取得・更新プロセスの構築コストが大幅に低下\u003c/strong\u003eしました。これまで複雑なAPI連携が必要だった処理が、ノーコードで実現できるようになったのです。\u003c/p\u003e\n\u003cp data-sourcepos=\"29:1-29:39\"\u003e主な利点は以下の通りです：\u003c/p\u003e\n\u003cul data-sourcepos=\"31:1-34:0\"\u003e\n\u003cli data-sourcepos=\"31:1-31:32\"\u003e構築コストの大幅低下\u003c/li\u003e\n\u003cli data-sourcepos=\"32:1-32:124\"\u003eノーコード化による実装時間短縮（簡易的なチャットボットであれば10分程度で作成可能）\u003c/li\u003e\n\u003cli data-sourcepos=\"33:1-34:0\"\u003ekintoneポータルへの埋め込みがスムーズに実施可能\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"35:1-35:121\"\u003eこの手軽さは、かつてkintoneが「脱エクセル」を実現した時の感覚に近いものがあります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"37:1-37:79\"\u003e\n\u003cspan id=\"初期検証で分かった構築の容易さと実務適用のギャップ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%88%9D%E6%9C%9F%E6%A4%9C%E8%A8%BC%E3%81%A7%E5%88%86%E3%81%8B%E3%81%A3%E3%81%9F%E6%A7%8B%E7%AF%89%E3%81%AE%E5%AE%B9%E6%98%93%E3%81%95%E3%81%A8%E5%AE%9F%E5%8B%99%E9%81%A9%E7%94%A8%E3%81%AE%E3%82%AE%E3%83%A3%E3%83%83%E3%83%97\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e初期検証で分かった構築の容易さと実務適用のギャップ\u003c/h3\u003e\n\u003cp data-sourcepos=\"39:1-39:205\"\u003eただし、基本構築が容易である一方で、実務に即した高度な自動化を実現するには、Difyの内部構造やワークフロー制御の習得が不可欠だと感じました。\u003c/p\u003e\n\u003cp data-sourcepos=\"41:1-41:204\"\u003e特に、複数のアプリを横断した処理や、条件に応じた分岐処理を組み込む際には、ノーコードツールとはいえ、ある程度の技術的理解が求められます。\u003c/p\u003e\n\u003cp data-sourcepos=\"43:1-43:236\"\u003eこの「簡単に始められるが、奥が深い」という特性は、kintoneと非常に似ています。だからこそ、kintone運用経験者にとっては親和性が高く、学習曲線も緩やかだと感じました。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"45:1-45:78\"\u003e\n\u003cspan id=\"kintoneアプリ設定の自動レビューaiを開発した背景と実装\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E3%82%A2%E3%83%97%E3%83%AA%E8%A8%AD%E5%AE%9A%E3%81%AE%E8%87%AA%E5%8B%95%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BCai%E3%82%92%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E8%83%8C%E6%99%AF%E3%81%A8%E5%AE%9F%E8%A3%85\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintoneアプリ設定の自動レビューAIを開発した背景と実装\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"47:1-47:73\"\u003e\n\u003cspan id=\"市民開発の拡大で顕在化したアプリ品質管理の課題\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%B8%82%E6%B0%91%E9%96%8B%E7%99%BA%E3%81%AE%E6%8B%A1%E5%A4%A7%E3%81%A7%E9%A1%95%E5%9C%A8%E5%8C%96%E3%81%97%E3%81%9F%E3%82%A2%E3%83%97%E3%83%AA%E5%93%81%E8%B3%AA%E7%AE%A1%E7%90%86%E3%81%AE%E8%AA%B2%E9%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e市民開発の拡大で顕在化したアプリ品質管理の課題\u003c/h3\u003e\n\u003cp data-sourcepos=\"49:1-49:295\"\u003e私たちの組織では、業務ユーザーにもkintoneアプリの市民開発を推進しています。アプリ作成ルールは定めているものの、日々アプリが増えていく中で、全てを人力でチェックすることが現実的に難しくなっていました。\u003c/p\u003e\n\u003cp data-sourcepos=\"51:1-51:69\"\u003e具体的には、以下のようなルールを設けています：\u003c/p\u003e\n\u003cul data-sourcepos=\"53:1-57:0\"\u003e\n\u003cli data-sourcepos=\"53:1-53:78\"\u003e\n\u003cstrong\u003e有効フラグを作成する\u003c/strong\u003e（削除権限を無効にするため）\u003c/li\u003e\n\u003cli data-sourcepos=\"54:1-54:111\"\u003e\n\u003cstrong\u003e重複禁止設定の確認\u003c/strong\u003e（複数項目で重複禁止になっている場合、不都合が多い）\u003c/li\u003e\n\u003cli data-sourcepos=\"55:1-55:48\"\u003e\u003cstrong\u003eフィールドコードは半角英数字\u003c/strong\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"56:1-57:0\"\u003e\n\u003cstrong\u003eレコード削除権限をはずす\u003c/strong\u003e（kintoneはレコード削除すると永久に失われるため）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"58:1-58:108\"\u003eこれらを毎回手作業で確認するのは、時間的にも精神的にも大きな負担でした。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"60:1-60:78\"\u003e\n\u003cspan id=\"公式レビューaiで期待通りの結果が得られなかった理由\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%85%AC%E5%BC%8F%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BCai%E3%81%A7%E6%9C%9F%E5%BE%85%E9%80%9A%E3%82%8A%E3%81%AE%E7%B5%90%E6%9E%9C%E3%81%8C%E5%BE%97%E3%82%89%E3%82%8C%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E7%90%86%E7%94%B1\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e公式レビューAIで期待通りの結果が得られなかった理由\u003c/h3\u003e\n\u003cp data-sourcepos=\"62:1-62:150\"\u003ekintone公式のアプリ設定レビューAIも存在していますが、実際に使ってみるといくつかの課題が見えてきました。\u003c/p\u003e\n\u003cp data-sourcepos=\"64:1-64:207\"\u003e例えば、有効フラグ項目が存在するのに、設定不備として判定されるなど、期待通りの出力が得られません。また、毎回回答が異なることも問題でした。\u003c/p\u003e\n\u003cp data-sourcepos=\"66:1-66:199\"\u003eさらに、1つずつしかレビューができないため、複数のアプリを一括でチェックしたい場合には時間がかかりすぎるという実務上の制約もあります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"68:1-68:68\"\u003e\n\u003cspan id=\"difyワークフローによる一括レビューの技術構成\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#dify%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AB%E3%82%88%E3%82%8B%E4%B8%80%E6%8B%AC%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AE%E6%8A%80%E8%A1%93%E6%A7%8B%E6%88%90\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eDifyワークフローによる一括レビューの技術構成\u003c/h3\u003e\n\u003cp data-sourcepos=\"70:1-70:99\"\u003eそこで、Difyを使って一括レビューできるAIアプリの開発に着手しました。\u003c/p\u003e\n\u003cp data-sourcepos=\"72:1-72:57\"\u003eワークフローの全体像は以下の通りです：\u003c/p\u003e\n\u003col data-sourcepos=\"74:1-79:0\"\u003e\n\u003cli data-sourcepos=\"74:1-74:45\"\u003ekintoneから複数のアプリIDを取得\u003c/li\u003e\n\u003cli data-sourcepos=\"75:1-75:77\"\u003eアプリID毎に、フィールド情報やアクセス権情報を取得\u003c/li\u003e\n\u003cli data-sourcepos=\"76:1-76:21\"\u003eLLMでレビュー\u003c/li\u003e\n\u003cli data-sourcepos=\"77:1-77:28\"\u003e結果をkintoneに返す\u003c/li\u003e\n\u003cli data-sourcepos=\"78:1-79:0\"\u003e終わるまでイテレーションで繰り返す\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp data-sourcepos=\"80:1-80:187\"\u003ekintoneアプリの構成には、テンプレートにある「アプリ管理」を流用し、レコードはCSVアプリ一覧の内容をレコード登録する形にしました。\u003c/p\u003e\n\u003cp data-sourcepos=\"82:1-82:287\"\u003e使用したノードは、\u003cstrong\u003ekintoneレコード取得\u003c/strong\u003e、\u003cstrong\u003eコード実行\u003c/strong\u003e、\u003cstrong\u003eイテレーション\u003c/strong\u003e、\u003cstrong\u003ekintoneアクセス権取得（カスタムノード）\u003c/strong\u003e、\u003cstrong\u003ekintoneフィールド情報取得（カスタムノード）\u003c/strong\u003e、\u003cstrong\u003eLLM\u003c/strong\u003e、\u003cstrong\u003ekintoneレコード更新\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp data-sourcepos=\"84:1-84:162\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F4405830%2Fc0a5f71b-b524-4841-98a4-c8c705ccb113.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=e857a6fc545bbe7b6fce8fac2eecee10\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F4405830%2Fc0a5f71b-b524-4841-98a4-c8c705ccb113.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=e857a6fc545bbe7b6fce8fac2eecee10\" alt=\"スクリーンショット 2026-04-14 092312.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F4405830%2Fc0a5f71b-b524-4841-98a4-c8c705ccb113.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=65ee551aee211b56bdbedbee0d0e8043 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4405830/c0a5f71b-b524-4841-98a4-c8c705ccb113.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 data-sourcepos=\"87:1-87:83\"\u003e\n\u003cspan id=\"カスタムノードでkintoneアクセス権取得機能を実装した手順\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%8E%E3%83%BC%E3%83%89%E3%81%A7kintone%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E6%A8%A9%E5%8F%96%E5%BE%97%E6%A9%9F%E8%83%BD%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E6%89%8B%E9%A0%86\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eカスタムノードでkintoneアクセス権取得機能を実装した手順\u003c/h3\u003e\n\u003cp data-sourcepos=\"89:1-89:181\"\u003e公式プラグインにアクセス権取得機能が含まれていなかったため、Difyのカスタム機能で取得するツールを作成する必要がありました。\u003c/p\u003e\n\u003cp data-sourcepos=\"91:1-91:249\"\u003e具体的には、kintoneのAPIリファレンスをGeminiに読み込ませて、OpenAPI仕様のスキーマを出力してもらいました。OpenAPI仕様テンプレートをベースに、必要な情報を構造化していく作業です。\u003c/p\u003e\n\u003cp data-sourcepos=\"93:1-93:163\"\u003eこの過程で、AIを使ってAPI仕様を理解させ、それを別のAIツールで活用するという、メタ的な構造に面白さを感じました。\u003c/p\u003e\n\u003cp data-sourcepos=\"95:1-95:102\"\u003e\u003cstrong\u003eAIが複数のレイヤーで連携する時代\u003c/strong\u003eが来ていることを実感できたのです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"97:1-97:90\"\u003e\n\u003cspan id=\"llmプロンプト設計4つのレビュー項目と対象外フィールドの定義\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#llm%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88%E8%A8%AD%E8%A8%884%E3%81%A4%E3%81%AE%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E9%A0%85%E7%9B%AE%E3%81%A8%E5%AF%BE%E8%B1%A1%E5%A4%96%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AE%E5%AE%9A%E7%BE%A9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eLLMプロンプト設計|4つのレビュー項目と対象外フィールドの定義\u003c/h3\u003e\n\u003cp data-sourcepos=\"99:1-99:97\"\u003eLLMに渡すプロンプトでは、以下の4つの確認項目を明確に定義しました：\u003c/p\u003e\n\u003col data-sourcepos=\"101:1-105:0\"\u003e\n\u003cli data-sourcepos=\"101:1-101:188\"\u003e\n\u003cstrong\u003e有効フラグ項目の確認\u003c/strong\u003e：チェックボックス、フィールド名「有効フラグ」、項目「yes」、初期値「yes」、フィールドコード「valid_flag」\u003c/li\u003e\n\u003cli data-sourcepos=\"102:1-102:131\"\u003e\n\u003cstrong\u003e重複禁止設定の確認\u003c/strong\u003e：重複禁止フィールドが1つのみ、社員番号・店舗コードなど適切か確認\u003c/li\u003e\n\u003cli data-sourcepos=\"103:1-103:106\"\u003e\n\u003cstrong\u003eフィールドコードの確認\u003c/strong\u003e：半角英数字とアンダースコアのみ、日本語なし\u003c/li\u003e\n\u003cli data-sourcepos=\"104:1-105:0\"\u003e\n\u003cstrong\u003eアクセス権設定の確認\u003c/strong\u003e：recordDeletableの値がfalse\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp data-sourcepos=\"106:1-106:87\"\u003eまた、以下のシステムフィールドは対象外として明示しました：\u003c/p\u003e\n\u003cul data-sourcepos=\"108:1-116:0\"\u003e\n\u003cli data-sourcepos=\"108:1-108:17\"\u003eカテゴリー\u003c/li\u003e\n\u003cli data-sourcepos=\"109:1-109:17\"\u003eステータス\u003c/li\u003e\n\u003cli data-sourcepos=\"110:1-110:20\"\u003eレコード番号\u003c/li\u003e\n\u003cli data-sourcepos=\"111:1-111:14\"\u003e作成日時\u003c/li\u003e\n\u003cli data-sourcepos=\"112:1-112:11\"\u003e作成者\u003c/li\u003e\n\u003cli data-sourcepos=\"113:1-113:11\"\u003e作業者\u003c/li\u003e\n\u003cli data-sourcepos=\"114:1-114:14\"\u003e更新日時\u003c/li\u003e\n\u003cli data-sourcepos=\"115:1-116:0\"\u003e更新者\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"117:1-117:195\"\u003e出力時の注意点として、XMLタグを含めない、改行は実際の改行、バックスラッシュやスラッシュは出力しないといった細かい指定も行いました。\u003c/p\u003e\n\u003cp data-sourcepos=\"119:1-119:118\"\u003eこれらの指定がないと、出力結果がkintoneに書き戻す際に正しく表示されないためです。\u003c/p\u003e\n\u003cp data-sourcepos=\"121:1-121:197\"\u003eなお、kintoneの情報を都度LLMに渡すとトークン消費が多くなるため、JavaScriptのコード実行ノードで必要な情報だけを抽出する処理を挟んでいます。\u003c/p\u003e\n\u003cp data-sourcepos=\"123:1-123:95\"\u003e例えば、total_countだけを取り出して次の処理に渡すといった工夫です。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"126:1-126:60\"\u003e\n\u003cspan id=\"aiモデル別の精度差sonnetとhaikuの出力比較\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#ai%E3%83%A2%E3%83%87%E3%83%AB%E5%88%A5%E3%81%AE%E7%B2%BE%E5%BA%A6%E5%B7%AEsonnet%E3%81%A8haiku%E3%81%AE%E5%87%BA%E5%8A%9B%E6%AF%94%E8%BC%83\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eAIモデル別の精度差|SonnetとHaikuの出力比較\u003c/h3\u003e\n\u003cp data-sourcepos=\"128:1-128:125\"\u003e同じプロンプトでも、使用するAIモデルによって出力の詳細度が異なることが分かりました。\u003c/p\u003e\n\u003cp data-sourcepos=\"130:1-130:22\"\u003e\u003cstrong\u003eSonnetの特性：\u003c/strong\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"131:1-134:0\"\u003e\n\u003cli data-sourcepos=\"131:1-131:71\"\u003eフィールドコードの修正例まで具体的に出力される\u003c/li\u003e\n\u003cli data-sourcepos=\"132:1-132:141\"\u003e例：「レコードの最終更新日」というフィールド名に対して「record_last_updated」といった修正例まで提示\u003c/li\u003e\n\u003cli data-sourcepos=\"133:1-134:0\"\u003e精度が高く、詳細な指摘が得られる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"135:1-135:21\"\u003e\u003cstrong\u003eHaikuの特性：\u003c/strong\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"136:1-139:0\"\u003e\n\u003cli data-sourcepos=\"136:1-136:74\"\u003eフィールド項目までの出力にとどまり、詳細度は劣る\u003c/li\u003e\n\u003cli data-sourcepos=\"137:1-137:23\"\u003e処理速度が速い\u003c/li\u003e\n\u003cli data-sourcepos=\"138:1-139:0\"\u003eコストが低い\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"140:1-140:121\"\u003e実務運用では、\u003cstrong\u003e精度とコストのバランス\u003c/strong\u003eを考慮してモデルを選択することが重要です。\u003c/p\u003e\n\u003cp data-sourcepos=\"142:1-142:149\"\u003e初期検証ではSonnetで詳細な出力を確認し、本格運用ではHaikuで効率化するといったアプローチも有効でしょう。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"144:1-144:49\"\u003e\n\u003cspan id=\"実装後に直面した2つの運用上の壁\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E5%BE%8C%E3%81%AB%E7%9B%B4%E9%9D%A2%E3%81%97%E3%81%9F2%E3%81%A4%E3%81%AE%E9%81%8B%E7%94%A8%E4%B8%8A%E3%81%AE%E5%A3%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装後に直面した2つの運用上の壁\u003c/h2\u003e\n\u003cp data-sourcepos=\"146:1-146:167\"\u003e設計通りにレビューしてくれるようになり、OK/NGが一目でわかり、具体的にどこを修正すればよいのかも明確になりました。\u003c/p\u003e\n\u003cp data-sourcepos=\"148:1-148:97\"\u003eしかし、実際の運用に向けては、2つの大きな壁が立ちはだかりました。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"150:1-150:96\"\u003e\n\u003cspan id=\"webhook利用時の永久ループ問題同一レコード書き戻しによる循環参照\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#webhook%E5%88%A9%E7%94%A8%E6%99%82%E3%81%AE%E6%B0%B8%E4%B9%85%E3%83%AB%E3%83%BC%E3%83%97%E5%95%8F%E9%A1%8C%E5%90%8C%E4%B8%80%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E6%9B%B8%E3%81%8D%E6%88%BB%E3%81%97%E3%81%AB%E3%82%88%E3%82%8B%E5%BE%AA%E7%92%B0%E5%8F%82%E7%85%A7\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eWebhook利用時の永久ループ問題|同一レコード書き戻しによる循環参照\u003c/h3\u003e\n\u003cp data-sourcepos=\"152:1-152:150\"\u003ekintoneの「レコード編集」をWebhookのトリガーに設定している場合、\u003cstrong\u003e永久ループが発生する可能性\u003c/strong\u003eがあります。\u003c/p\u003e\n\u003cp data-sourcepos=\"154:1-154:54\"\u003e具体的な発生フローは以下の通りです：\u003c/p\u003e\n\u003col data-sourcepos=\"156:1-161:0\"\u003e\n\u003cli data-sourcepos=\"156:1-156:45\"\u003eユーザーがレコードを保存する\u003c/li\u003e\n\u003cli data-sourcepos=\"157:1-157:40\"\u003eWebhookが飛び、DifyのAIが動く\u003c/li\u003e\n\u003cli data-sourcepos=\"158:1-158:109\"\u003eDifyが計算結果やレビュー結果を、同じレコードの特定のフィールドに書き戻す\u003c/li\u003e\n\u003cli data-sourcepos=\"159:1-159:92\"\u003ekintone側は「レコードが更新された」とみなし、再度Webhookを飛ばす\u003c/li\u003e\n\u003cli data-sourcepos=\"160:1-161:0\"\u003e1〜4が永遠に繰り返される\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp data-sourcepos=\"162:1-162:287\"\u003eこの問題は、ステータスの更新やアプリ循環の更新など、Webhookを使用する際に常に意識しなければならない課題です。\u003cstrong\u003e同一レコードへの書き戻しによる循環参照を避けるための設計\u003c/strong\u003eが不可欠だと痛感しました。\u003c/p\u003e\n\u003cp data-sourcepos=\"164:1-164:78\"\u003e対策としては、以下のようなアプローチが考えられます：\u003c/p\u003e\n\u003cul data-sourcepos=\"166:1-169:0\"\u003e\n\u003cli data-sourcepos=\"166:1-166:44\"\u003e更新対象フィールドを限定する\u003c/li\u003e\n\u003cli data-sourcepos=\"167:1-167:47\"\u003eステータスで処理済みを判定する\u003c/li\u003e\n\u003cli data-sourcepos=\"168:1-169:0\"\u003e別レコードに結果を記録する\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"170:1-170:118\"\u003e\n\u003cspan id=\"外部aiに渡すユーザー権限のジレンマアプリ設定閲覧とレコード操作権限の分離不可\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%A4%96%E9%83%A8ai%E3%81%AB%E6%B8%A1%E3%81%99%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E6%A8%A9%E9%99%90%E3%81%AE%E3%82%B8%E3%83%AC%E3%83%B3%E3%83%9E%E3%82%A2%E3%83%97%E3%83%AA%E8%A8%AD%E5%AE%9A%E9%96%B2%E8%A6%A7%E3%81%A8%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E6%93%8D%E4%BD%9C%E6%A8%A9%E9%99%90%E3%81%AE%E5%88%86%E9%9B%A2%E4%B8%8D%E5%8F%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e外部AIに渡すユーザー権限のジレンマ|アプリ設定閲覧とレコード操作権限の分離不可\u003c/h3\u003e\n\u003cp data-sourcepos=\"172:1-172:67\"\u003eもう一つの大きな壁が、\u003cstrong\u003e権限設計の問題\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp data-sourcepos=\"174:1-174:153\"\u003e外部AI(DifyやClaude等)にkintoneのアプリ構造を理解させつつ、セキュアに運用する際の権限ジレンマに直面しました。\u003c/p\u003e\n\u003cp data-sourcepos=\"176:1-176:269\"\u003eアプリの設定情報を一括取得するには「kintone共通管理者」権限が必須です。しかし、これを与えるとシステム共通管理画面の全操作が可能になり、\u003cstrong\u003eガバナンス上のリスクが極めて大きくなります\u003c/strong\u003e。\u003c/p\u003e\n\u003cp data-sourcepos=\"178:1-178:186\"\u003e一方、アプリごとに権限を振る方法もありますが、全てのアプリに設定作業が必要になり、アプリ数が多い場合は現実的ではありません。\u003c/p\u003e\n\u003cp data-sourcepos=\"180:1-180:99\"\u003e各ユーザー権限における「アプリ設定閲覧」の限界も明確になりました：\u003c/p\u003e\n\u003cblockquote data-sourcepos=\"182:1-182:318\"\u003e\n\u003cp data-sourcepos=\"182:3-182:318\"\u003e\u003cstrong\u003eシステム共通管理者\u003c/strong\u003eの場合、全アプリのアプリ設定が閲覧可能ですが、スペースに所属しなければレコード操作は防げるものの、システム共通管理画面の権限そのものを外部ツールに渡すのはセキュリティ上極めて危うい状況です。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote data-sourcepos=\"184:1-184:274\"\u003e\n\u003cp data-sourcepos=\"184:3-184:274\"\u003e\u003cstrong\u003eシステム管理者\u003c/strong\u003eや\u003cstrong\u003e通常ユーザー\u003c/strong\u003eの場合、アプリ設定を見るには「スペースへの所属」および「アプリ管理権限」が必要ですが、スペースに所属した時点でレコード操作が可能になってしまいます。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp data-sourcepos=\"186:1-186:243\"\u003e理想的には、「レコードの取得・登録・更新・削除」といったデータ操作権限を一切持たせない、あるいは明確に除外できる\u003cstrong\u003e設定情報参照(Read-only)への特化\u003c/strong\u003eが求められています。\u003c/p\u003e\n\u003cp data-sourcepos=\"188:1-188:209\"\u003e全アプリの構造(フィールド情報・設定値)のみを取得できる専用権限があれば、この問題は解決するのですが、現時点ではそうした仕組みは存在しません。\u003c/p\u003e\n\u003cp data-sourcepos=\"190:1-190:172\"\u003eこの権限設計の課題は、\u003cstrong\u003ekintoneとAIツールを連携させる上で、多くの組織が直面するであろう普遍的な問題\u003c/strong\u003eだと感じています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"192:1-192:57\"\u003e\n\u003cspan id=\"開発を通じて得られた成果と今後の展望\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E9%96%8B%E7%99%BA%E3%82%92%E9%80%9A%E3%81%98%E3%81%A6%E5%BE%97%E3%82%89%E3%82%8C%E3%81%9F%E6%88%90%E6%9E%9C%E3%81%A8%E4%BB%8A%E5%BE%8C%E3%81%AE%E5%B1%95%E6%9C%9B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e開発を通じて得られた成果と今後の展望\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"194:1-194:85\"\u003e\n\u003cspan id=\"設計通りのレビュー実現okng判定と具体的修正箇所の可視化\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E9%80%9A%E3%82%8A%E3%81%AE%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E5%AE%9F%E7%8F%BEokng%E5%88%A4%E5%AE%9A%E3%81%A8%E5%85%B7%E4%BD%93%E7%9A%84%E4%BF%AE%E6%AD%A3%E7%AE%87%E6%89%80%E3%81%AE%E5%8F%AF%E8%A6%96%E5%8C%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e設計通りのレビュー実現|OK/NG判定と具体的修正箇所の可視化\u003c/h3\u003e\n\u003cp data-sourcepos=\"196:1-196:182\"\u003e公式のレビューでは毎回回答が異なっていましたが、Difyで構築したシステムでは、\u003cstrong\u003e設計通りに安定したレビューが実現\u003c/strong\u003eできました。\u003c/p\u003e\n\u003cp data-sourcepos=\"198:1-198:188\"\u003eOK/NGが一目でわかることに加え、具体的にどこを修正すればよいのかも明確に提示されるため、実務上の価値は非常に高いと感じています。\u003c/p\u003e\n\u003cp data-sourcepos=\"200:1-200:197\"\u003e技術的な課題は残っているものの、「AIが人間の作業を補完し、品質を担保する」という仕組みの可能性を実感できたことは、大きな成果でした。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"202:1-202:62\"\u003e\n\u003cspan id=\"kintone導入時に似た脱手作業への期待感\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E5%B0%8E%E5%85%A5%E6%99%82%E3%81%AB%E4%BC%BC%E3%81%9F%E8%84%B1%E6%89%8B%E4%BD%9C%E6%A5%AD%E3%81%B8%E3%81%AE%E6%9C%9F%E5%BE%85%E6%84%9F\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone導入時に似た「脱手作業」への期待感\u003c/h3\u003e\n\u003cp data-sourcepos=\"204:1-204:139\"\u003e容易なAIアプリ作成やkintone連携により、kintone導入時の「脱エクセル」に似た高揚感を実感しています。\u003c/p\u003e\n\u003cp data-sourcepos=\"206:1-206:105\"\u003e従来の手作業（ポチポチ確認）から解放されるという強い期待感があります。\u003c/p\u003e\n\u003cp data-sourcepos=\"208:1-208:117\"\u003eこの「ワクワク感」は、新しい技術を導入する際の大きなモチベーションになります。\u003c/p\u003e\n\u003cp data-sourcepos=\"210:1-210:141\"\u003e完璧でなくても、少しずつ改善していけば、いずれ大きな業務効率化につながるという確信があります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"212:1-212:83\"\u003e\n\u003cspan id=\"エコシステムの親和性学習リソースとコミュニティの充実\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%A8%E3%82%B3%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E8%A6%AA%E5%92%8C%E6%80%A7%E5%AD%A6%E7%BF%92%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%A8%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3%E3%81%AE%E5%85%85%E5%AE%9F\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eエコシステムの親和性|学習リソースとコミュニティの充実\u003c/h3\u003e\n\u003cp data-sourcepos=\"214:1-214:193\"\u003eDifyには、活発なユーザー会、豊富な学習リソース(YouTube、Udemy、書籍)など、kintoneと共通した「学びやすく、繋がりやすい」文化圏があります。\u003c/p\u003e\n\u003cp data-sourcepos=\"216:1-216:143\"\u003eサポート体制が充実しており、\u003cstrong\u003ekintoneに近いコミュニティの熱量\u003c/strong\u003eを感じられることも、大きな魅力です。\u003c/p\u003e\n\u003cp data-sourcepos=\"218:1-218:195\"\u003e技術的な課題に直面した時、同じような悩みを持つ仲間がいて、情報交換できる環境があることは、実務担当者にとって非常に心強いものです。\u003c/p\u003e\n\u003chr data-sourcepos=\"220:1-221:0\"\u003e\n\u003ch2 data-sourcepos=\"222:1-222:12\"\u003e\n\u003cspan id=\"最後に\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%9C%80%E5%BE%8C%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e最後に\u003c/h2\u003e\n\u003cp data-sourcepos=\"224:1-224:61\"\u003ekintone×Dify連携は、まだ発展途上の領域です。\u003c/p\u003e\n\u003cp data-sourcepos=\"226:1-226:88\"\u003e権限設計やWebhook設計など、解決すべき課題も多く残っています。\u003c/p\u003e\n\u003cp data-sourcepos=\"228:1-228:112\"\u003eしかし、だからこそ、\u003cstrong\u003e今このタイミングで取り組む価値がある\u003c/strong\u003eと感じています。\u003c/p\u003e\n\u003cp data-sourcepos=\"230:1-230:225\"\u003eもしあなたの組織でkintoneを運用していて、「データをもっと活用したい」「AIとの連携を検討したい」と考えているなら、まずは小さな検証から始めてみてください。\u003c/p\u003e\n\u003cp data-sourcepos=\"232:1-232:138\"\u003e完璧を目指すのではなく、一つずつ課題を解決していく過程そのものが、大きな学びになるはずです。\u003c/p\u003e\n\u003cp data-sourcepos=\"234:1-234:75\"\u003e私自身も、この開発を通じて多くの気づきを得ました。\u003c/p\u003e\n\u003cp data-sourcepos=\"236:1-236:119\"\u003e今後も試行錯誤を続けながら、実務に即したAI活用の形を模索していきたいと思います。\u003c/p\u003e\n\u003cp data-sourcepos=\"238:1-238:126\"\u003eあなたの組織での小さな一歩が、やがて大きな業務効率化へとつながることを願っています。\u003c/p\u003e\n","body":"![スクリーンショット 2026-04-14 091807.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4405830/ceddfbb6-d6c8-467c-ab47-47ae5346ccd0.png)\n\n\n「kintoneにデータは溜まっているけど、うまく活用できていない」\n「AIツールとの連携って、どうやって始めればいいんだろう」\n\n社内でkintoneを運用している情報システム担当者の方なら、こうした悩みを一度は感じたことがあるのではないでしょうか。私自身、kintoneの市民開発を推進する立場として、日々増え続けるアプリの品質管理に頭を抱えていました。\n\nそんな中、Difyの公式kintoneコネクタが実装されたことをきっかけに、実際にAIを活用したアプリ設定の自動レビューシステムを開発してみました。この記事では、その過程で得られた技術的な知見と、運用上の壁、そして今後の可能性について、実務担当者の視点から詳しくお伝えします。\n\n##### ※本記事はkintoneに保存した日々の作業メモを元に、Dify（AIエージェント）を活用して構成・執筆しています。\n\n## kintone×Dify連携を検討する前に知っておくべき基礎知識\n\n### Difyとは何か\n\n**Dify**は、LLM(大規模言語モデル)と外部ツールをノーコードで連結できるAI開発プラットフォームです。\n\n単なるチャットボット構築ツールではなく、条件分岐や繰り返し処理を伴う複雑なワークフローの自動化が可能な点が特徴です。\n\n私がDifyに注目したのは、社内でClaude、n8nなどのAI活用が活性化していた時期のこと。\n\n業界イベントでDify×kintone連携の情報を得て、すぐに検証を開始しました。従来のAPI連携と異なり、ノーコードで複雑な業務フローを構築できる可能性に魅力を感じたのです。\n\n### kintone公式コネクタの実装で何が変わったのか\n\nDifyの公式kintoneコネクタが実装されたことで、**データの取得・更新プロセスの構築コストが大幅に低下**しました。これまで複雑なAPI連携が必要だった処理が、ノーコードで実現できるようになったのです。\n\n主な利点は以下の通りです：\n\n- 構築コストの大幅低下\n- ノーコード化による実装時間短縮（簡易的なチャットボットであれば10分程度で作成可能）\n- kintoneポータルへの埋め込みがスムーズに実施可能\n\nこの手軽さは、かつてkintoneが「脱エクセル」を実現した時の感覚に近いものがあります。\n\n### 初期検証で分かった構築の容易さと実務適用のギャップ\n\nただし、基本構築が容易である一方で、実務に即した高度な自動化を実現するには、Difyの内部構造やワークフロー制御の習得が不可欠だと感じました。\n\n特に、複数のアプリを横断した処理や、条件に応じた分岐処理を組み込む際には、ノーコードツールとはいえ、ある程度の技術的理解が求められます。\n\nこの「簡単に始められるが、奥が深い」という特性は、kintoneと非常に似ています。だからこそ、kintone運用経験者にとっては親和性が高く、学習曲線も緩やかだと感じました。\n\n## kintoneアプリ設定の自動レビューAIを開発した背景と実装\n\n### 市民開発の拡大で顕在化したアプリ品質管理の課題\n\n私たちの組織では、業務ユーザーにもkintoneアプリの市民開発を推進しています。アプリ作成ルールは定めているものの、日々アプリが増えていく中で、全てを人力でチェックすることが現実的に難しくなっていました。\n\n具体的には、以下のようなルールを設けています：\n\n- **有効フラグを作成する**（削除権限を無効にするため）\n- **重複禁止設定の確認**（複数項目で重複禁止になっている場合、不都合が多い）\n- **フィールドコードは半角英数字**\n- **レコード削除権限をはずす**（kintoneはレコード削除すると永久に失われるため）\n\nこれらを毎回手作業で確認するのは、時間的にも精神的にも大きな負担でした。\n\n### 公式レビューAIで期待通りの結果が得られなかった理由\n\nkintone公式のアプリ設定レビューAIも存在していますが、実際に使ってみるといくつかの課題が見えてきました。\n\n例えば、有効フラグ項目が存在するのに、設定不備として判定されるなど、期待通りの出力が得られません。また、毎回回答が異なることも問題でした。\n\nさらに、1つずつしかレビューができないため、複数のアプリを一括でチェックしたい場合には時間がかかりすぎるという実務上の制約もあります。\n\n### Difyワークフローによる一括レビューの技術構成\n\nそこで、Difyを使って一括レビューできるAIアプリの開発に着手しました。\n\nワークフローの全体像は以下の通りです：\n\n1. kintoneから複数のアプリIDを取得\n2. アプリID毎に、フィールド情報やアクセス権情報を取得\n3. LLMでレビュー\n4. 結果をkintoneに返す\n5. 終わるまでイテレーションで繰り返す\n\nkintoneアプリの構成には、テンプレートにある「アプリ管理」を流用し、レコードはCSVアプリ一覧の内容をレコード登録する形にしました。\n\n使用したノードは、**kintoneレコード取得**、**コード実行**、**イテレーション**、**kintoneアクセス権取得（カスタムノード）**、**kintoneフィールド情報取得（カスタムノード）**、**LLM**、**kintoneレコード更新**です。\n\n![スクリーンショット 2026-04-14 092312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4405830/c0a5f71b-b524-4841-98a4-c8c705ccb113.png)\n\n\n### カスタムノードでkintoneアクセス権取得機能を実装した手順\n\n公式プラグインにアクセス権取得機能が含まれていなかったため、Difyのカスタム機能で取得するツールを作成する必要がありました。\n\n具体的には、kintoneのAPIリファレンスをGeminiに読み込ませて、OpenAPI仕様のスキーマを出力してもらいました。OpenAPI仕様テンプレートをベースに、必要な情報を構造化していく作業です。\n\nこの過程で、AIを使ってAPI仕様を理解させ、それを別のAIツールで活用するという、メタ的な構造に面白さを感じました。\n\n**AIが複数のレイヤーで連携する時代**が来ていることを実感できたのです。\n\n### LLMプロンプト設計|4つのレビュー項目と対象外フィールドの定義\n\nLLMに渡すプロンプトでは、以下の4つの確認項目を明確に定義しました：\n\n1. **有効フラグ項目の確認**：チェックボックス、フィールド名「有効フラグ」、項目「yes」、初期値「yes」、フィールドコード「valid_flag」\n2. **重複禁止設定の確認**：重複禁止フィールドが1つのみ、社員番号・店舗コードなど適切か確認\n3. **フィールドコードの確認**：半角英数字とアンダースコアのみ、日本語なし\n4. **アクセス権設定の確認**：recordDeletableの値がfalse\n\nまた、以下のシステムフィールドは対象外として明示しました：\n\n- カテゴリー\n- ステータス\n- レコード番号\n- 作成日時\n- 作成者\n- 作業者\n- 更新日時\n- 更新者\n\n出力時の注意点として、XMLタグを含めない、改行は実際の改行、バックスラッシュやスラッシュは出力しないといった細かい指定も行いました。\n\nこれらの指定がないと、出力結果がkintoneに書き戻す際に正しく表示されないためです。\n\nなお、kintoneの情報を都度LLMに渡すとトークン消費が多くなるため、JavaScriptのコード実行ノードで必要な情報だけを抽出する処理を挟んでいます。\n\n例えば、total_countだけを取り出して次の処理に渡すといった工夫です。\n\n\n### AIモデル別の精度差|SonnetとHaikuの出力比較\n\n同じプロンプトでも、使用するAIモデルによって出力の詳細度が異なることが分かりました。\n\n**Sonnetの特性：**\n- フィールドコードの修正例まで具体的に出力される\n- 例：「レコードの最終更新日」というフィールド名に対して「record_last_updated」といった修正例まで提示\n- 精度が高く、詳細な指摘が得られる\n\n**Haikuの特性：**\n- フィールド項目までの出力にとどまり、詳細度は劣る\n- 処理速度が速い\n- コストが低い\n\n実務運用では、**精度とコストのバランス**を考慮してモデルを選択することが重要です。\n\n初期検証ではSonnetで詳細な出力を確認し、本格運用ではHaikuで効率化するといったアプローチも有効でしょう。\n\n## 実装後に直面した2つの運用上の壁\n\n設計通りにレビューしてくれるようになり、OK/NGが一目でわかり、具体的にどこを修正すればよいのかも明確になりました。\n\nしかし、実際の運用に向けては、2つの大きな壁が立ちはだかりました。\n\n### Webhook利用時の永久ループ問題|同一レコード書き戻しによる循環参照\n\nkintoneの「レコード編集」をWebhookのトリガーに設定している場合、**永久ループが発生する可能性**があります。\n\n具体的な発生フローは以下の通りです：\n\n1. ユーザーがレコードを保存する\n2. Webhookが飛び、DifyのAIが動く\n3. Difyが計算結果やレビュー結果を、同じレコードの特定のフィールドに書き戻す\n4. kintone側は「レコードが更新された」とみなし、再度Webhookを飛ばす\n5. 1〜4が永遠に繰り返される\n\nこの問題は、ステータスの更新やアプリ循環の更新など、Webhookを使用する際に常に意識しなければならない課題です。**同一レコードへの書き戻しによる循環参照を避けるための設計**が不可欠だと痛感しました。\n\n対策としては、以下のようなアプローチが考えられます：\n\n- 更新対象フィールドを限定する\n- ステータスで処理済みを判定する\n- 別レコードに結果を記録する\n\n### 外部AIに渡すユーザー権限のジレンマ|アプリ設定閲覧とレコード操作権限の分離不可\n\nもう一つの大きな壁が、**権限設計の問題**です。\n\n外部AI(DifyやClaude等)にkintoneのアプリ構造を理解させつつ、セキュアに運用する際の権限ジレンマに直面しました。\n\nアプリの設定情報を一括取得するには「kintone共通管理者」権限が必須です。しかし、これを与えるとシステム共通管理画面の全操作が可能になり、**ガバナンス上のリスクが極めて大きくなります**。\n\n一方、アプリごとに権限を振る方法もありますが、全てのアプリに設定作業が必要になり、アプリ数が多い場合は現実的ではありません。\n\n各ユーザー権限における「アプリ設定閲覧」の限界も明確になりました：\n\n\u003e **システム共通管理者**の場合、全アプリのアプリ設定が閲覧可能ですが、スペースに所属しなければレコード操作は防げるものの、システム共通管理画面の権限そのものを外部ツールに渡すのはセキュリティ上極めて危うい状況です。\n\n\u003e **システム管理者**や**通常ユーザー**の場合、アプリ設定を見るには「スペースへの所属」および「アプリ管理権限」が必要ですが、スペースに所属した時点でレコード操作が可能になってしまいます。\n\n理想的には、「レコードの取得・登録・更新・削除」といったデータ操作権限を一切持たせない、あるいは明確に除外できる**設定情報参照(Read-only)への特化**が求められています。\n\n全アプリの構造(フィールド情報・設定値)のみを取得できる専用権限があれば、この問題は解決するのですが、現時点ではそうした仕組みは存在しません。\n\nこの権限設計の課題は、**kintoneとAIツールを連携させる上で、多くの組織が直面するであろう普遍的な問題**だと感じています。\n\n## 開発を通じて得られた成果と今後の展望\n\n### 設計通りのレビュー実現|OK/NG判定と具体的修正箇所の可視化\n\n公式のレビューでは毎回回答が異なっていましたが、Difyで構築したシステムでは、**設計通りに安定したレビューが実現**できました。\n\nOK/NGが一目でわかることに加え、具体的にどこを修正すればよいのかも明確に提示されるため、実務上の価値は非常に高いと感じています。\n\n技術的な課題は残っているものの、「AIが人間の作業を補完し、品質を担保する」という仕組みの可能性を実感できたことは、大きな成果でした。\n\n### kintone導入時に似た「脱手作業」への期待感\n\n容易なAIアプリ作成やkintone連携により、kintone導入時の「脱エクセル」に似た高揚感を実感しています。\n\n従来の手作業（ポチポチ確認）から解放されるという強い期待感があります。\n\nこの「ワクワク感」は、新しい技術を導入する際の大きなモチベーションになります。\n\n完璧でなくても、少しずつ改善していけば、いずれ大きな業務効率化につながるという確信があります。\n\n### エコシステムの親和性|学習リソースとコミュニティの充実\n\nDifyには、活発なユーザー会、豊富な学習リソース(YouTube、Udemy、書籍)など、kintoneと共通した「学びやすく、繋がりやすい」文化圏があります。\n\nサポート体制が充実しており、**kintoneに近いコミュニティの熱量**を感じられることも、大きな魅力です。\n\n技術的な課題に直面した時、同じような悩みを持つ仲間がいて、情報交換できる環境があることは、実務担当者にとって非常に心強いものです。\n\n---\n\n## 最後に\n\nkintone×Dify連携は、まだ発展途上の領域です。\n\n権限設計やWebhook設計など、解決すべき課題も多く残っています。\n\nしかし、だからこそ、**今このタイミングで取り組む価値がある**と感じています。\n\nもしあなたの組織でkintoneを運用していて、「データをもっと活用したい」「AIとの連携を検討したい」と考えているなら、まずは小さな検証から始めてみてください。\n\n完璧を目指すのではなく、一つずつ課題を解決していく過程そのものが、大きな学びになるはずです。\n\n私自身も、この開発を通じて多くの気づきを得ました。\n\n今後も試行錯誤を続けながら、実務に即したAI活用の形を模索していきたいと思います。\n\nあなたの組織での小さな一歩が、やがて大きな業務効率化へとつながることを願っています。\n","coediting":false,"comments_count":0,"created_at":"2026-04-16T10:06:27+09:00","group":null,"id":"4af78bf83463c31fcab5","likes_count":2,"private":false,"reactions_count":0,"stocks_count":1,"tags":[{"name":"kintone","versions":[]},{"name":"Dify","versions":[]}],"title":"kintone×Dify連携で社内データをAI活用する方法","updated_at":"2026-04-16T10:06:27+09:00","url":"https://qiita.com/syusuket/items/4af78bf83463c31fcab5","user":{"description":null,"facebook_id":null,"followees_count":1,"followers_count":0,"github_login_name":null,"id":"syusuket","items_count":1,"linkedin_id":null,"location":null,"name":"","organization":null,"permanent_id":4405830,"profile_image_url":"https://secure.gravatar.com/avatar/9564c5d0258cf8dafb385043f4f6455f","team_only":false,"twitter_screen_name":null,"website_url":null},"page_views_count":null,"team_membership":null,"organization_url_name":"genda_jp","slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:171\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F605275%2Fd9976f2f-efc8-4a25-966e-309764606fdf.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=464e612b821bf5229e23c040bd43a26a\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F605275%2Fd9976f2f-efc8-4a25-966e-309764606fdf.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=464e612b821bf5229e23c040bd43a26a\" alt=\"サムネ作成用 (1200 x 630 px) (2400 x 1200 px) (6).png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F605275%2Fd9976f2f-efc8-4a25-966e-309764606fdf.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=e9dcf58c482a1b536aaaadd67ee3364d 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/d9976f2f-efc8-4a25-966e-309764606fdf.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch3 data-sourcepos=\"3:1-3:158\"\u003e\n\u003cspan id=\"414-解禁設計書作成からアプリ自動生成へ簡単なクリック操作でkintoneアプリの構築を効率化する新機能\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#414-%E8%A7%A3%E7%A6%81%E8%A8%AD%E8%A8%88%E6%9B%B8%E4%BD%9C%E6%88%90%E3%81%8B%E3%82%89%E3%82%A2%E3%83%97%E3%83%AA%E8%87%AA%E5%8B%95%E7%94%9F%E6%88%90%E3%81%B8%E7%B0%A1%E5%8D%98%E3%81%AA%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E6%93%8D%E4%BD%9C%E3%81%A7kintone%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E6%A7%8B%E7%AF%89%E3%82%92%E5%8A%B9%E7%8E%87%E5%8C%96%E3%81%99%E3%82%8B%E6%96%B0%E6%A9%9F%E8%83%BD\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4/14 解禁：設計書作成から「アプリ自動生成」へ。簡単なクリック操作でkintoneアプリの構築を効率化する新機能🚀\u003c/h3\u003e\n\u003cp data-sourcepos=\"5:1-5:368\"\u003eこれまでもレクシン AIは、業務改善の会議のメモや文字おこしから、アプリ設計書や業務フロー図などのドキュメントをワンクリックで自動生成することで、kintoneで自社業務を改善したい皆様やお客様への提案をスピードアップさせたいSIerの皆様をサポートしてきました。\u003c/p\u003e\n\u003cp data-sourcepos=\"7:1-7:80\"\u003e2026年4月14日に、レクシン AI for kintoneはさらに進化します。\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-13:126\"\u003eこれまでの「設計書を自動で生成する」機能に加えて、ついに \u003cstrong\u003e「kintoneアプリそのものを自動で生成する機能 」をリリース\u003c/strong\u003e することになりました。\u003cbr\u003e\n「AIが書いた設計書を見ながら、自分の手でkintoneの設定画面をポチポチ埋めていく」という、あの最後の手間さえ、もういりません。これからは、「kintoneの知識を持ったAIが設計をして、そのままボタンのクリックでアプリが出来上がる」。\u003cbr\u003e\nしかし、なぜ単なる文章要約ツールではなく「kintoneの実機を作るAI」を創ることにこだわったのか。\u003cbr\u003e\nその背景には、ノベルワークスの開発現場で抱えていた苦悩がありました。\u003cbr\u003e\n今回は、最新機能リリース記念として、レクシン AIが誕生した秘話をお話しさせてください。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"15:1-15:84\"\u003e\n\u003cspan id=\"-始まりは売るためではなく自社の不便を救うため\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E5%A7%8B%E3%81%BE%E3%82%8A%E3%81%AF%E5%A3%B2%E3%82%8B%E3%81%9F%E3%82%81%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E8%87%AA%E7%A4%BE%E3%81%AE%E4%B8%8D%E4%BE%BF%E3%82%92%E6%95%91%E3%81%86%E3%81%9F%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🚩 始まりは、売るためではなく「自社の不便」を救うため\u003c/h3\u003e\n\u003cp data-sourcepos=\"17:1-18:107\"\u003e実は、レクシン AIは、もともとは販売するためではなく、私たち自身が現場で抱えていた「不便」を解消するために生まれたツールです。\u003cbr\u003e\n長年kintoneの開発に携わる中で、私たちは2つの大きな壁にぶつかっていました。\u003c/p\u003e\n\u003cp data-sourcepos=\"20:1-21:125\"\u003e\u003cstrong\u003e・効率の壁： 「お客様を待たせず、もっとスピーディーに本質的な改善ができないか？」\u003c/strong\u003e\u003cbr\u003e\n\u003cstrong\u003e・属人化の壁： 「ヒアリング漏れを防ぎ、誰が見ても分かる設計を担保できているか？」\u003c/strong\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"23:1-24:207\"\u003eそこで自分たちの業務効率化のため、エンジニアの知見を詰め込んで作ったのがレクシン AI（2024年ベータ版）でした。\u003cbr\u003e\n実際に自社で活用を始めると、業務がスムーズになり、これまで苦労していたドキュメント作成の時間が、「お客様への提案時間」へと変わったのです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"26:1-26:57\"\u003e\n\u003cspan id=\"-汎用aiでは届かないkintoneの深淵\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E6%B1%8E%E7%94%A8ai%E3%81%A7%E3%81%AF%E5%B1%8A%E3%81%8B%E3%81%AA%E3%81%84kintone%E3%81%AE%E6%B7%B1%E6%B7%B5\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e💡 汎用AIでは届かない「kintoneの深淵」\u003c/h3\u003e\n\u003cp data-sourcepos=\"28:1-30:280\"\u003e汎用AIは「一般論」は語れても、kintone特有の制約や「正しいリレーションの組み方」までは導き出せません。\u003cbr\u003e\nそこで私たちは、「kintone独自の構築ルールやノウハウに基づき、最適なアプリ構造を導き出す手法」をロジック化し、 \u003cstrong\u003e特許（第7765117号）を取得\u003c/strong\u003e しました。\u003cbr\u003e\nこの特許技術があるからこそ、ユーザーは難しいことを考えず、AIが提示する選択肢をクリックして進めるだけで、精度の高い設計の土台（ER図や業務フロー）を手に入れることができるようになったのです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"32:1-32:70\"\u003e\n\u003cspan id=\"-4月14日ついに考えるaiから作るaiへ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-4%E6%9C%8814%E6%97%A5%E3%81%A4%E3%81%84%E3%81%AB%E8%80%83%E3%81%88%E3%82%8Bai%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8Bai%E3%81%B8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🏁 4月14日、ついに「考えるAI」から「作るAI」へ\u003c/h3\u003e\n\u003cp data-sourcepos=\"34:1-35:128\"\u003e2026年4月14日。\u003cbr\u003e\n私たちが社内で活用し、磨き上げてきた 「アプリ自動生成機能」 を、ついにリリースします。\u003c/p\u003e\n\u003cp data-sourcepos=\"37:1-38:179\"\u003eこれまでは「レクシン AIが提案した設計書を見て、人間がkintoneで作る」というステップが必要でしたが、これからは \u003cstrong\u003e「kintone知能を持ったAIが設計し、そのままボタンクリックでアプリを作る」ことが可能\u003c/strong\u003e になります。\u003cbr\u003e\nこれまで多くの時間と労力を要していた作業をAIに託し、人間がより本質的でクリエイティブな業務に集中できる未来を目指します。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"40:1-40:59\"\u003e\n\u003cspan id=\"-私たちが目指すワクワクする未来\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E7%A7%81%E3%81%9F%E3%81%A1%E3%81%8C%E7%9B%AE%E6%8C%87%E3%81%99%E3%83%AF%E3%82%AF%E3%83%AF%E3%82%AF%E3%81%99%E3%82%8B%E6%9C%AA%E6%9D%A5\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e✨ 私たちが目指す「ワクワクする未来」\u003c/h3\u003e\n\u003cp data-sourcepos=\"41:1-43:141\"\u003e私たちノベルワークスのミッションは、「テクノロジーと人の力で、ワクワクする未来を創造すること」です。\u003cbr\u003e\nテクノロジーの力で単純な「作業」を減らし、人が本来持っている「考える力」や「創造性」を取り戻す。\u003cbr\u003e\n4月14日のアップデートが、皆さまの現場に「ワクワクする未来」をもたらすきっかけになれば幸いです。\u003c/p\u003e\n\u003ch4 data-sourcepos=\"46:1-46:66\"\u003e\n\u003cspan id=\"レクシン-ai-for-kintone公式webサイトはこちら\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%B3-ai-for-kintone%E5%85%AC%E5%BC%8Fweb%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AF%E3%81%93%E3%81%A1%E3%82%89\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e👉レクシン AI for kintone公式WEBサイトはこちら\u003c/h4\u003e\n\u003cp data-sourcepos=\"48:1-48:24\"\u003e\u003ciframe id=\"qiita-embed-content__98f69242f46a4360d7cdce6b31c34291\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__98f69242f46a4360d7cdce6b31c34291\" data-content=\"https%3A%2F%2Fwww.reqxign.net%2F\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\"\u003e\n\u003c/iframe\u003e\n\u003c/p\u003e\n","body":"![サムネ作成用 (1200 x 630 px) (2400 x 1200 px) (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/d9976f2f-efc8-4a25-966e-309764606fdf.png)\n\n### 4/14 解禁：設計書作成から「アプリ自動生成」へ。簡単なクリック操作でkintoneアプリの構築を効率化する新機能🚀\n\nこれまでもレクシン AIは、業務改善の会議のメモや文字おこしから、アプリ設計書や業務フロー図などのドキュメントをワンクリックで自動生成することで、kintoneで自社業務を改善したい皆様やお客様への提案をスピードアップさせたいSIerの皆様をサポートしてきました。\n\n2026年4月14日に、レクシン AI for kintoneはさらに進化します。 \n\nこれまでの「設計書を自動で生成する」機能に加えて、ついに **「kintoneアプリそのものを自動で生成する機能 」をリリース** することになりました。\n「AIが書いた設計書を見ながら、自分の手でkintoneの設定画面をポチポチ埋めていく」という、あの最後の手間さえ、もういりません。これからは、「kintoneの知識を持ったAIが設計をして、そのままボタンのクリックでアプリが出来上がる」。\nしかし、なぜ単なる文章要約ツールではなく「kintoneの実機を作るAI」を創ることにこだわったのか。\nその背景には、ノベルワークスの開発現場で抱えていた苦悩がありました。\n今回は、最新機能リリース記念として、レクシン AIが誕生した秘話をお話しさせてください。\n\n### 🚩 始まりは、売るためではなく「自社の不便」を救うため\n\n実は、レクシン AIは、もともとは販売するためではなく、私たち自身が現場で抱えていた「不便」を解消するために生まれたツールです。\n長年kintoneの開発に携わる中で、私たちは2つの大きな壁にぶつかっていました。\n\n**・効率の壁： 「お客様を待たせず、もっとスピーディーに本質的な改善ができないか？」**\n**・属人化の壁： 「ヒアリング漏れを防ぎ、誰が見ても分かる設計を担保できているか？」**\n\nそこで自分たちの業務効率化のため、エンジニアの知見を詰め込んで作ったのがレクシン AI（2024年ベータ版）でした。\n実際に自社で活用を始めると、業務がスムーズになり、これまで苦労していたドキュメント作成の時間が、「お客様への提案時間」へと変わったのです。\n\n### 💡 汎用AIでは届かない「kintoneの深淵」\n\n汎用AIは「一般論」は語れても、kintone特有の制約や「正しいリレーションの組み方」までは導き出せません。\nそこで私たちは、「kintone独自の構築ルールやノウハウに基づき、最適なアプリ構造を導き出す手法」をロジック化し、 **特許（第7765117号）を取得** しました。\nこの特許技術があるからこそ、ユーザーは難しいことを考えず、AIが提示する選択肢をクリックして進めるだけで、精度の高い設計の土台（ER図や業務フロー）を手に入れることができるようになったのです。\n\n### 🏁 4月14日、ついに「考えるAI」から「作るAI」へ\n\n2026年4月14日。\n私たちが社内で活用し、磨き上げてきた 「アプリ自動生成機能」 を、ついにリリースします。\n\nこれまでは「レクシン AIが提案した設計書を見て、人間がkintoneで作る」というステップが必要でしたが、これからは **「kintone知能を持ったAIが設計し、そのままボタンクリックでアプリを作る」ことが可能** になります。\nこれまで多くの時間と労力を要していた作業をAIに託し、人間がより本質的でクリエイティブな業務に集中できる未来を目指します。\n\n### ✨ 私たちが目指す「ワクワクする未来」\n私たちノベルワークスのミッションは、「テクノロジーと人の力で、ワクワクする未来を創造すること」です。\nテクノロジーの力で単純な「作業」を減らし、人が本来持っている「考える力」や「創造性」を取り戻す。\n4月14日のアップデートが、皆さまの現場に「ワクワクする未来」をもたらすきっかけになれば幸いです。\n\n\n#### 👉レクシン AI for kintone公式WEBサイトはこちら\n\nhttps://www.reqxign.net/\n\n\n","coediting":false,"comments_count":0,"created_at":"2026-04-13T10:06:34+09:00","group":null,"id":"c01dbc20e92626a4d78c","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"AI","versions":[]},{"name":"アプリ開発","versions":[]},{"name":"kintone","versions":[]},{"name":"kintoneplugin","versions":[]}],"title":"### 【4/14新機能リリース】「アプリ自動生成機能」がついに解禁。 ～kintone開発の新しいスタンダード「レクシン AI for kintone」誕生秘話～","updated_at":"2026-04-13T10:06:34+09:00","url":"https://qiita.com/novelworks/items/c01dbc20e92626a4d78c","user":{"description":"kintoneやAWSの開発を行っている大阪の会社です。\r\n念願のR\u0026Dチームも結成されこれからバンバン情報発信していきます！","facebook_id":"","followees_count":15,"followers_count":9,"github_login_name":null,"id":"novelworks","items_count":29,"linkedin_id":"","location":"大阪府大阪市西区靱本町2ｰ2ｰ12","name":"株式会社 ノベルワークス","organization":"株式会社ノベルワークス","permanent_id":605275,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/605275/e6afe7c7de81b82da3ca9385eac8cd1f032998d7/x_large.png?1591580536","team_only":false,"twitter_screen_name":null,"website_url":"https://www.novelworks.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:123\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F98fd798f-445d-4cb4-abaa-dfb633efb411.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=975e412edd3e902d2ffd725dca72d4f4\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F98fd798f-445d-4cb4-abaa-dfb633efb411.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=975e412edd3e902d2ffd725dca72d4f4\" alt=\"day010.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F98fd798f-445d-4cb4-abaa-dfb633efb411.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=c054b3fae93677513c65bf6987fdc2f1 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/98fd798f-445d-4cb4-abaa-dfb633efb411.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"5:1-6:76\"\u003e面倒解決エンジニアの森田ユウゴです。\u003cbr\u003e\n台湾からお届けする「#kintone100日チャレンジ」の10日目。\u003c/p\u003e\n\u003cp data-sourcepos=\"8:1-8:107\"\u003e👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジの概要はこちら\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"10:1-11:153\"\u003e本日は、スマホやタブレットで現場入力を行う現場作業員向けの「\u003cstrong\u003eモバイルQRコードリーダー\u003c/strong\u003e」プラグインを開発しました！\u003cbr\u003e\n昨日\u003ca href=\"https://qiita.com/majinalife/items/828355a2bf2776635d40\" id=\"reference-4582ecc9a0a8bcc96aac\"\u003eDay009\u003c/a\u003eで作成したQRコードメーカーのQRコードを読み取る機能です。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"13:1-13:56\"\u003e\n\u003cspan id=\"モバイルqrコードリーダーについて\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%A2%E3%83%90%E3%82%A4%E3%83%ABqr%E3%82%B3%E3%83%BC%E3%83%89%E3%83%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e「モバイルQRコードリーダー」について\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"14:1-14:75\"\u003e\n\u003cspan id=\"-なぜ開発したか現場の課題とベネフィット\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%AA%E3%81%9C%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E3%81%8B%E7%8F%BE%E5%A0%B4%E3%81%AE%E8%AA%B2%E9%A1%8C%E3%81%A8%E3%83%99%E3%83%8D%E3%83%95%E3%82%A3%E3%83%83%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🎯 なぜ開発したか？（現場の課題とベネフィット）\u003c/h3\u003e\n\u003cul data-sourcepos=\"15:1-17:0\"\u003e\n\u003cli data-sourcepos=\"15:1-15:254\"\u003e\n\u003cstrong\u003e現場の「不」:\u003c/strong\u003e スマートフォンの小さな画面で、屋外や立ったままの状態で文字入力やドロップダウンの選択を行うのはストレスであり、入力ミスや作業遅延の大きな原因になります。\u003c/li\u003e\n\u003cli data-sourcepos=\"16:1-17:0\"\u003e\n\u003cstrong\u003e導入後の世界（ベネフィット）:\u003c/strong\u003e 昨日のDay 9で開発した「QRコードメーカー」と連携し、生成されたQRコードをスマホカメラで読み取るだけで、レコードの各フィールドへ一瞬で自動入力！手入力によるストレスとミスを根絶し、現場のデータ登録作業を爆速化します！\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"18:1-18:50\"\u003e\n\u003cspan id=\"-これで出来ること機能概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%93%E3%82%8C%E3%81%A7%E5%87%BA%E6%9D%A5%E3%82%8B%E3%81%93%E3%81%A8%E6%A9%9F%E8%83%BD%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e✨ これで出来ること（機能概要）\u003c/h3\u003e\n\u003cp data-sourcepos=\"19:1-19:42\"\u003eまずはこちらをご覧ください。\u003c/p\u003e\n\u003ciframe width=\"100%\" height=\"315\" src=\"https://www.youtube.com/embed/gszdIm65XjA\" frameborder=\"0\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cul data-sourcepos=\"23:1-26:0\"\u003e\n\u003cli data-sourcepos=\"23:1-23:281\"\u003e\n\u003cstrong\u003eスマホカメラでのQR読み取り機能:\u003c/strong\u003e モバイル版のレコード追加・編集画面に「QR読取」ボタンを配置。ボタンをタップすると全画面のオーバーレイで端末の背面カメラが起動し、QRコードを連続解析します。\u003c/li\u003e\n\u003cli data-sourcepos=\"24:1-24:264\"\u003e\n\u003cstrong\u003e読み取りデータの自動マージ（反映）:\u003c/strong\u003e jsQRライブラリを使用してデコードしたkintone JSON形式のデータを解析し、現在のレコードのフィールドへ型をチェックしながら安全に自動セットします。\u003c/li\u003e\n\u003cli data-sourcepos=\"25:1-26:0\"\u003e\n\u003cstrong\u003e柔軟なボタン配置:\u003c/strong\u003e プラグイン設定画面から、読み取りボタンの表示先を「ヘッダー領域」または「指定した複数のスペースフィールド」から選択可能。現場の使い勝手に合わせたUI設計が可能です。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"27:1-27:10\"\u003e\n\u003cspan id=\"課題\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%AA%B2%E9%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e課題\u003c/h3\u003e\n\u003cp data-sourcepos=\"28:1-28:63\"\u003e現時点では下記のような課題が残っています。\u003c/p\u003e\n\u003cul data-sourcepos=\"30:1-36:0\"\u003e\n\u003cli data-sourcepos=\"30:1-31:218\"\u003e\n\u003cstrong\u003eカメラ起動エラーのハンドリングと現場への配慮\u003c/strong\u003e\u003cbr\u003e\n今回は前日の「009プロジェクト」のJSON仕様をベースに作成したため、AIとのバイブスコーディング自体は非常にスムーズで大きなトラブルはありませんでした。\u003c/li\u003e\n\u003cli data-sourcepos=\"32:1-36:0\"\u003e\n\u003cstrong\u003e仕様の非柔軟性\u003c/strong\u003e\u003cbr\u003e\nこれは昨日作成したQRコードメーカーにも関連しますが、レコードデータだけを対象にしています。\u003cbr\u003e\nそのため、細かい状況ごとにQRコードを分ける必要があります。\u003cbr\u003e\nこの点は何か改善できないか…。と思いながらDay10開発は終了します。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"37:1-37:15\"\u003e\n\u003cspan id=\"さいごに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eさいごに\u003c/h2\u003e\n\u003cp data-sourcepos=\"39:1-40:102\"\u003eDay 9で作った「生成」と本日の「読み取り」、この2つが組み合わさることでモバイル業務の自動化が一気に現実味を帯びてきますね。\u003cbr\u003e\nこの点は、具体的な必要とされる業務の解像度が低い所が悔やまれます…。\u003c/p\u003e\n\u003cp data-sourcepos=\"42:1-42:27\"\u003e明日もお楽しみに！\u003c/p\u003e\n\u003cp data-sourcepos=\"44:1-46:180\"\u003e下記のブログもご覧ください！\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！\u003c/a\u003e\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/kintone-support-service-coconala/\" rel=\"nofollow noopener\" target=\"_blank\"\u003eココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"48:1-48:114\"\u003e2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\u003c/p\u003e\n\u003cblockquote class=\"twitter-tweet\"\u003e\n\u003cp\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e— 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003eApril 15, 2026\u003c/a\u003e\n\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\"\u003e\u003c/script\u003e\n","body":"![day010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/98fd798f-445d-4cb4-abaa-dfb633efb411.png)\n\n\n\n面倒解決エンジニアの森田ユウゴです。\n台湾からお届けする「#kintone100日チャレンジ」の10日目。\n\n👉 [#kintone100日チャレンジの概要はこちら](https://moritayugo.com/100days-of-kintone-hacks/)\n\n本日は、スマホやタブレットで現場入力を行う現場作業員向けの「**モバイルQRコードリーダー**」プラグインを開発しました！\n昨日[Day009](https://qiita.com/majinalife/items/828355a2bf2776635d40)で作成したQRコードメーカーのQRコードを読み取る機能です。\n\n## 「モバイルQRコードリーダー」について\n### 🎯 なぜ開発したか？（現場の課題とベネフィット）\n- **現場の「不」:** スマートフォンの小さな画面で、屋外や立ったままの状態で文字入力やドロップダウンの選択を行うのはストレスであり、入力ミスや作業遅延の大きな原因になります。\n- **導入後の世界（ベネフィット）:** 昨日のDay 9で開発した「QRコードメーカー」と連携し、生成されたQRコードをスマホカメラで読み取るだけで、レコードの各フィールドへ一瞬で自動入力！手入力によるストレスとミスを根絶し、現場のデータ登録作業を爆速化します！\n\n### ✨ これで出来ること（機能概要）\nまずはこちらをご覧ください。\n\n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/gszdIm65XjA\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\n- **スマホカメラでのQR読み取り機能:** モバイル版のレコード追加・編集画面に「QR読取」ボタンを配置。ボタンをタップすると全画面のオーバーレイで端末の背面カメラが起動し、QRコードを連続解析します。\n- **読み取りデータの自動マージ（反映）:** jsQRライブラリを使用してデコードしたkintone JSON形式のデータを解析し、現在のレコードのフィールドへ型をチェックしながら安全に自動セットします。\n- **柔軟なボタン配置:** プラグイン設定画面から、読み取りボタンの表示先を「ヘッダー領域」または「指定した複数のスペースフィールド」から選択可能。現場の使い勝手に合わせたUI設計が可能です。\n\n### 課題\n現時点では下記のような課題が残っています。\n\n- **カメラ起動エラーのハンドリングと現場への配慮**\n  今回は前日の「009プロジェクト」のJSON仕様をベースに作成したため、AIとのバイブスコーディング自体は非常にスムーズで大きなトラブルはありませんでした。\n- **仕様の非柔軟性**\n  これは昨日作成したQRコードメーカーにも関連しますが、レコードデータだけを対象にしています。\n  そのため、細かい状況ごとにQRコードを分ける必要があります。\n  この点は何か改善できないか…。と思いながらDay10開発は終了します。\n\n## さいごに\n\nDay 9で作った「生成」と本日の「読み取り」、この2つが組み合わさることでモバイル業務の自動化が一気に現実味を帯びてきますね。\nこの点は、具体的な必要とされる業務の解像度が低い所が悔やまれます…。\n\n明日もお楽しみに！\n\n下記のブログもご覧ください！\n👉 [【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！](https://moritayugo.com/100days-of-kintone-hacks/)\n👉 [ココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！](https://moritayugo.com/kintone-support-service-coconala/)\n\n2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\n\u003cblockquote class=\"twitter-tweet\"\u003e\u003cp lang=\"ja\" dir=\"ltr\"\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e\u0026mdash; 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\"\u003eApril 15, 2026\u003c/a\u003e\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\n","coediting":false,"comments_count":0,"created_at":"2026-04-10T17:31:27+09:00","group":null,"id":"a75777407f85ea33acc6","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"kintoneplugin","versions":[]},{"name":"バイブコーディング","versions":[]},{"name":"kintoneカスタマイズ","versions":[]},{"name":"kintone100日チャレンジ","versions":[]}],"title":"【#kintone100日チャレンジ】Day 10: モバイル入力を効率化する準備に「QRコードリーダー for kintone」を作ってみた","updated_at":"2026-04-15T09:55:54+09:00","url":"https://qiita.com/majinalife/items/a75777407f85ea33acc6","user":{"description":"台湾在住の「面倒解決エンジニア」です。\r\n#kintone #Anki Chrome拡張など得意分野です💻\r\nアプリデザインスペシャリスト(2025)\r\nカスタマイズスペシャリスト(2026) \r\nお仕事のご依頼を承っておりますのでお気軽にご相談ください！","facebook_id":"","followees_count":1,"followers_count":1,"github_login_name":null,"id":"majinalife","items_count":13,"linkedin_id":"","location":"台湾","name":"森田 ユウゴ","organization":"","permanent_id":3990248,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3990248/795e2d2e68ab72ba29dc3224f01546c658346fc2/large.png?1774234714","team_only":false,"twitter_screen_name":"majinalife_blog","website_url":"https://moritayugo.com/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:123\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2Fe4287707-e2b6-496f-a90a-91d3727f5379.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=1540c3fac1d1fee7587de9c86e1ea7a3\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2Fe4287707-e2b6-496f-a90a-91d3727f5379.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=1540c3fac1d1fee7587de9c86e1ea7a3\" alt=\"day009.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2Fe4287707-e2b6-496f-a90a-91d3727f5379.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=c9a84763253e940f108b7fabf17fedce 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/e4287707-e2b6-496f-a90a-91d3727f5379.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-4:75\"\u003e面倒解決エンジニアの森田ユウゴです。\u003cbr\u003e\n台湾からお届けする「#kintone100日チャレンジ」の9日目。\u003c/p\u003e\n\u003cp data-sourcepos=\"6:1-6:107\"\u003e👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジの概要はこちら\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"8:1-10:85\"\u003e本日は、モバイルでデータ入力を行う現場作業員向けの「\u003cstrong\u003eQRコードメーカー for kintone\u003c/strong\u003e」を開発しました！\u003cbr\u003e\n気が付けばチャレンジの1桁目は今日で終わりです。\u003cbr\u003e\nつまり、クルーズ旅行から帰ってきて9日目か…、早いな。。。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"12:1-12:56\"\u003e\n\u003cspan id=\"qrコードメーカー-for-kintoneについて\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#qr%E3%82%B3%E3%83%BC%E3%83%89%E3%83%A1%E3%83%BC%E3%82%AB%E3%83%BC-for-kintone%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e「QRコードメーカー for kintone」について\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"13:1-13:75\"\u003e\n\u003cspan id=\"-なぜ開発したか現場の課題とベネフィット\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%AA%E3%81%9C%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E3%81%8B%E7%8F%BE%E5%A0%B4%E3%81%AE%E8%AA%B2%E9%A1%8C%E3%81%A8%E3%83%99%E3%83%8D%E3%83%95%E3%82%A3%E3%83%83%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🎯 なぜ開発したか？（現場の課題とベネフィット）\u003c/h3\u003e\n\u003cul data-sourcepos=\"14:1-16:0\"\u003e\n\u003cli data-sourcepos=\"14:1-14:252\"\u003e\n\u003cstrong\u003e現場の「不」:\u003c/strong\u003e スマートフォンからkintoneにアクセスし、小さな画面で文字入力やドロップダウン選択をポチポチと行うのは非常に手間であり、現場での入力ミスの原因にもなります。\u003c/li\u003e\n\u003cli data-sourcepos=\"15:1-16:0\"\u003e\n\u003cstrong\u003e導入後の世界（ベネフィット）:\u003c/strong\u003e PC側で作成されたレコード情報をQRコード化しておくことで、スマホのカメラやバーコードリーダーで読み取るだけで別アプリ等への入力支援が可能に。スマホでの手入力を極力ゼロにする省力化を実現するために、本日はQRコード生成に着目しました！\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"17:1-17:134\"\u003e※明日はこのプラグインで生成したQRコードをもとに、レコード登録するプラグインを開発予定です\u003c/p\u003e\n\u003ch3 data-sourcepos=\"19:1-19:50\"\u003e\n\u003cspan id=\"-これで出来ること機能概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%93%E3%82%8C%E3%81%A7%E5%87%BA%E6%9D%A5%E3%82%8B%E3%81%93%E3%81%A8%E6%A9%9F%E8%83%BD%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e✨ これで出来ること（機能概要）\u003c/h3\u003e\n\u003cp data-sourcepos=\"20:1-20:42\"\u003eまずはこちらをご覧ください。\u003c/p\u003e\n\u003ciframe width=\"100%\" height=\"315\" src=\"https://www.youtube.com/embed/AOPAmmc9aA4\" frameborder=\"0\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cul data-sourcepos=\"24:1-27:0\"\u003e\n\u003cli data-sourcepos=\"24:1-24:303\"\u003e\n\u003cstrong\u003eレコードデータのJSON＆QR化:\u003c/strong\u003e 詳細画面でボタンを押すだけで、設定した対象フィールドの値をkintone標準のJSON形式で抽出し、QRコードを自動生成します。（※内部処理にはMITライセンスの \u003ccode\u003eqrcode-browser.js\u003c/code\u003e を使用しています）\u003c/li\u003e\n\u003cli data-sourcepos=\"25:1-25:208\"\u003e\n\u003cstrong\u003e添付ファイルフィールドへの自動保存:\u003c/strong\u003e 生成したQRコード画像（PNG）は、指定した添付ファイルフィールドへ自動的にアップロードされ保存されます。\u003c/li\u003e\n\u003cli data-sourcepos=\"26:1-27:0\"\u003e\n\u003cstrong\u003eKUCを用いた直感的な設定画面:\u003c/strong\u003e プラグイン設定画面では、QRコードに含めたいフィールドや保存先の添付フィールドを、kintone UI Component (KUC) のリッチなUIから簡単にチェック＆選択できます。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"28:1-28:10\"\u003e\n\u003cspan id=\"課題\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%AA%B2%E9%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e課題\u003c/h3\u003e\n\u003cp data-sourcepos=\"29:1-29:63\"\u003e現時点では下記のような課題が残っています。\u003c/p\u003e\n\u003cul data-sourcepos=\"30:1-39:0\"\u003e\n\u003cli data-sourcepos=\"30:1-31:418\"\u003e\n\u003cstrong\u003eUIとスペースフィールド配置の手間\u003c/strong\u003e\u003cbr\u003e\nQRコード生成ボタンの配置用としてスペースフィールドを用意するのは「若干」手間がかかります。ヘッダーメニュー領域への配置も可能ですが、他のボタンと被って邪魔になりがちです。今回は「ビジネスロジック的に添付ファイルの横にスペースを置いて表示する」想定で作りましたが、悩みどころです。\u003c/li\u003e\n\u003cli data-sourcepos=\"32:1-36:101\"\u003e\n\u003cstrong\u003eAIの添付に関するREST APIの雑な実装とエラーハンドリング\u003c/strong\u003e\u003cbr\u003e\n初期のバイブコーディング時、kintoneの添付に関する処理は非常にもろく安定しませんでした。\u003cbr\u003e\n当然、developer networkの情報を提供するのですが、5往復くらいは指示した記憶です。\u003cbr\u003e\n一方、指示する際、「違う、○○じゃないとダメ」みたいな雑な指示で修正出来るAIは凄い。\u003cbr\u003e\nここらへんのロジックはモデルとして学習が不足しているんだなと実感。\u003c/li\u003e\n\u003cli data-sourcepos=\"37:1-39:0\"\u003e\n\u003cstrong\u003e現場の業務シナリオ解像度と汎用性の不足\u003c/strong\u003e\u003cbr\u003e\n「レコードデータをテンプレート化し、別アプリの入力支援に使う」というロジックで本当に現場に刺さるのか、モバイル運用特化の業務経験が弱いため手探りな部分がありました。また、既存市場のQRコードプラグインとの比較調査が甘かった。というか市場調査していない…。今後はレコードデータだけでなく、より汎用的なカスタムデータを組み込めるような拡張も検討したいです。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"40:1-40:15\"\u003e\n\u003cspan id=\"さいごに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eさいごに\u003c/h2\u003e\n\u003cp data-sourcepos=\"42:1-42:78\"\u003e\u003cstrong\u003eQRコードは株式会社デンソーウェーブの登録商標です。\u003c/strong\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"44:1-45:123\"\u003e余談ですが昨日から動画編集にDaVinci Resolveを使っています。\u003cbr\u003e\n有料版を買うつもりですが、この程度の動画なら無料版で十分過ぎるので感動しています。\u003c/p\u003e\n\u003cp data-sourcepos=\"47:1-47:27\"\u003e明日もお楽しみに！\u003c/p\u003e\n\u003cp data-sourcepos=\"49:1-51:180\"\u003e下記のブログもご覧ください！\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！\u003c/a\u003e\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/kintone-support-service-coconala/\" rel=\"nofollow noopener\" target=\"_blank\"\u003eココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"53:1-53:114\"\u003e2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\u003c/p\u003e\n\u003cblockquote class=\"twitter-tweet\"\u003e\n\u003cp\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e— 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003eApril 15, 2026\u003c/a\u003e\n\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\"\u003e\u003c/script\u003e\n","body":"![day009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/e4287707-e2b6-496f-a90a-91d3727f5379.png)\n\n面倒解決エンジニアの森田ユウゴです。\n台湾からお届けする「#kintone100日チャレンジ」の9日目。\n\n👉 [#kintone100日チャレンジの概要はこちら](https://moritayugo.com/100days-of-kintone-hacks/)\n\n本日は、モバイルでデータ入力を行う現場作業員向けの「**QRコードメーカー for kintone**」を開発しました！\n気が付けばチャレンジの1桁目は今日で終わりです。\nつまり、クルーズ旅行から帰ってきて9日目か…、早いな。。。\n\n## 「QRコードメーカー for kintone」について\n### 🎯 なぜ開発したか？（現場の課題とベネフィット）\n- **現場の「不」:** スマートフォンからkintoneにアクセスし、小さな画面で文字入力やドロップダウン選択をポチポチと行うのは非常に手間であり、現場での入力ミスの原因にもなります。\n- **導入後の世界（ベネフィット）:** PC側で作成されたレコード情報をQRコード化しておくことで、スマホのカメラやバーコードリーダーで読み取るだけで別アプリ等への入力支援が可能に。スマホでの手入力を極力ゼロにする省力化を実現するために、本日はQRコード生成に着目しました！\n\n※明日はこのプラグインで生成したQRコードをもとに、レコード登録するプラグインを開発予定です\n\n### ✨ これで出来ること（機能概要）\nまずはこちらをご覧ください。\n\n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/AOPAmmc9aA4\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\n- **レコードデータのJSON＆QR化:** 詳細画面でボタンを押すだけで、設定した対象フィールドの値をkintone標準のJSON形式で抽出し、QRコードを自動生成します。（※内部処理にはMITライセンスの `qrcode-browser.js` を使用しています）\n- **添付ファイルフィールドへの自動保存:** 生成したQRコード画像（PNG）は、指定した添付ファイルフィールドへ自動的にアップロードされ保存されます。\n- **KUCを用いた直感的な設定画面:** プラグイン設定画面では、QRコードに含めたいフィールドや保存先の添付フィールドを、kintone UI Component (KUC) のリッチなUIから簡単にチェック＆選択できます。\n\n### 課題\n現時点では下記のような課題が残っています。\n- **UIとスペースフィールド配置の手間**\n  QRコード生成ボタンの配置用としてスペースフィールドを用意するのは「若干」手間がかかります。ヘッダーメニュー領域への配置も可能ですが、他のボタンと被って邪魔になりがちです。今回は「ビジネスロジック的に添付ファイルの横にスペースを置いて表示する」想定で作りましたが、悩みどころです。\n- **AIの添付に関するREST APIの雑な実装とエラーハンドリング**\n  初期のバイブコーディング時、kintoneの添付に関する処理は非常にもろく安定しませんでした。\n  当然、developer networkの情報を提供するのですが、5往復くらいは指示した記憶です。\n  一方、指示する際、「違う、○○じゃないとダメ」みたいな雑な指示で修正出来るAIは凄い。\n  ここらへんのロジックはモデルとして学習が不足しているんだなと実感。\n- **現場の業務シナリオ解像度と汎用性の不足**\n  「レコードデータをテンプレート化し、別アプリの入力支援に使う」というロジックで本当に現場に刺さるのか、モバイル運用特化の業務経験が弱いため手探りな部分がありました。また、既存市場のQRコードプラグインとの比較調査が甘かった。というか市場調査していない…。今後はレコードデータだけでなく、より汎用的なカスタムデータを組み込めるような拡張も検討したいです。\n\n## さいごに\n\n**QRコードは株式会社デンソーウェーブの登録商標です。**\n\n余談ですが昨日から動画編集にDaVinci Resolveを使っています。\n有料版を買うつもりですが、この程度の動画なら無料版で十分過ぎるので感動しています。\n\n明日もお楽しみに！\n\n下記のブログもご覧ください！\n👉 [【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！](https://moritayugo.com/100days-of-kintone-hacks/)\n👉 [ココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！](https://moritayugo.com/kintone-support-service-coconala/)\n\n2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\n\u003cblockquote class=\"twitter-tweet\"\u003e\u003cp lang=\"ja\" dir=\"ltr\"\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e\u0026mdash; 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\"\u003eApril 15, 2026\u003c/a\u003e\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\n","coediting":false,"comments_count":0,"created_at":"2026-04-09T17:53:07+09:00","group":null,"id":"828355a2bf2776635d40","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"kintoneplugin","versions":[]},{"name":"バイブコーディング","versions":[]},{"name":"kintoneカスタマイズ","versions":[]},{"name":"kintone100日チャレンジ","versions":[]}],"title":"【#kintone100日チャレンジ】Day 9: モバイル入力を効率化する準備に「QRコードメーカー for kintone」を作ってみた","updated_at":"2026-04-15T09:55:53+09:00","url":"https://qiita.com/majinalife/items/828355a2bf2776635d40","user":{"description":"台湾在住の「面倒解決エンジニア」です。\r\n#kintone #Anki Chrome拡張など得意分野です💻\r\nアプリデザインスペシャリスト(2025)\r\nカスタマイズスペシャリスト(2026) \r\nお仕事のご依頼を承っておりますのでお気軽にご相談ください！","facebook_id":"","followees_count":1,"followers_count":1,"github_login_name":null,"id":"majinalife","items_count":13,"linkedin_id":"","location":"台湾","name":"森田 ユウゴ","organization":"","permanent_id":3990248,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3990248/795e2d2e68ab72ba29dc3224f01546c658346fc2/large.png?1774234714","team_only":false,"twitter_screen_name":"majinalife_blog","website_url":"https://moritayugo.com/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:94\"\u003ekintone を SQL ライクに扱える \u003ccode\u003ekintone-sql-tools\u003c/code\u003e を作成したので紹介します\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-3:16\"\u003eリポジトリ:\u003c/p\u003e\n\u003cul data-sourcepos=\"5:1-6:0\"\u003e\n\u003cli data-sourcepos=\"5:1-6:0\"\u003e\u003ca href=\"https://github.com/rex0220/kintone-sql-tools\" class=\"autolink\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://github.com/rex0220/kintone-sql-tools\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"7:1-7:12\"\u003e関連記事\u003c/p\u003e\n\u003cul data-sourcepos=\"9:1-11:0\"\u003e\n\u003cli data-sourcepos=\"9:1-9:86\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/ed9e101cb28b0ed40869\" id=\"reference-49ec9162e4600e72c342\"\u003erex0220 kSQL プラグイン\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"10:1-11:0\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/e089fddf4229d74be699\" id=\"reference-7b36a2d3a195ad827d0a\"\u003erex0220 kSQL 言語リファレンス\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"12:1-12:15\"\u003e\n\u003cspan id=\"はじめに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eはじめに\u003c/h2\u003e\n\u003cp data-sourcepos=\"14:1-16:42\"\u003ekintone のデータ確認や抽出をするとき、\u003cbr\u003e\n「一覧を作るほどではないけど、条件を少し指定して取りたい」\u003cbr\u003e\nという場面は多いと思います。\u003c/p\u003e\n\u003cp data-sourcepos=\"18:1-18:102\"\u003e\u003ccode\u003ekintone-sql-tools\u003c/code\u003e は、kintone アプリを SQL 風の構文で扱えるツールセットです。\u003c/p\u003e\n\u003cul data-sourcepos=\"20:1-22:0\"\u003e\n\u003cli data-sourcepos=\"20:1-20:17\"\u003eCLI（\u003ccode\u003eksql\u003c/code\u003e）\u003c/li\u003e\n\u003cli data-sourcepos=\"21:1-22:0\"\u003ekintone プラグイン（UI）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"23:1-23:78\"\u003eの 2 つを用意していて、用途に応じて使い分けできます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"25:1-25:18\"\u003e\n\u003cspan id=\"できること\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eできること\u003c/h2\u003e\n\u003cp data-sourcepos=\"27:1-27:45\"\u003e主な対応機能は次のとおりです。\u003c/p\u003e\n\u003cul data-sourcepos=\"29:1-34:0\"\u003e\n\u003cli data-sourcepos=\"29:1-29:54\"\u003e\n\u003ccode\u003eSELECT\u003c/code\u003e（JOIN / GROUP BY / HAVING / CTE / UNION）\u003c/li\u003e\n\u003cli data-sourcepos=\"30:1-30:11\"\u003e\u003ccode\u003eEXPLAIN\u003c/code\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"31:1-31:69\"\u003e\n\u003ccode\u003eINSERT\u003c/code\u003e / \u003ccode\u003eUPDATE\u003c/code\u003e / \u003ccode\u003eUPSERT\u003c/code\u003e / \u003ccode\u003eDELETE\u003c/code\u003e（\u003ccode\u003e--allow-dml\u003c/code\u003e 必須）\u003c/li\u003e\n\u003cli data-sourcepos=\"32:1-32:59\"\u003eサブテーブル仮想テーブル（\u003ccode\u003eAPP100$明細\u003c/code\u003e）\u003c/li\u003e\n\u003cli data-sourcepos=\"33:1-34:0\"\u003eCLI 拡張 \u003ccode\u003eAPP@profile\u003c/code\u003e（環境切替）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"35:1-35:15\"\u003e\n\u003cspan id=\"前提条件\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e前提条件\u003c/h2\u003e\n\u003cul data-sourcepos=\"37:1-40:0\"\u003e\n\u003cli data-sourcepos=\"37:1-37:38\"\u003eNode.js 18 以上（CLI 利用時）\u003c/li\u003e\n\u003cli data-sourcepos=\"38:1-38:34\"\u003ekintone 環境と対象アプリ\u003c/li\u003e\n\u003cli data-sourcepos=\"39:1-40:0\"\u003eAPI トークン（CLI で token 認証を使う場合）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"41:1-41:28\"\u003e\n\u003cspan id=\"cli-のインストール\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#cli-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eCLI のインストール\u003c/h2\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"43:1-46:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003enpm \u003cspan class=\"nb\"\u003einstall\u003c/span\u003e \u003cspan class=\"nt\"\u003e-g\u003c/span\u003e @rex0220/kintone-sql-tools\nksql \u003cspan class=\"nt\"\u003e--help\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"48:1-48:43\"\u003e\n\u003cspan id=\"kintone-プラグインuiの場所\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone-%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3ui%E3%81%AE%E5%A0%B4%E6%89%80\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone プラグイン（UI）の場所\u003c/h2\u003e\n\u003cp data-sourcepos=\"50:1-50:89\"\u003eプラグイン版はリポジトリの \u003ccode\u003erelease\u003c/code\u003e フォルダに配置しています。\u003c/p\u003e\n\u003cul data-sourcepos=\"52:1-55:0\"\u003e\n\u003cli data-sourcepos=\"52:1-52:96\"\u003e\n\u003ccode\u003erelease/ksql-plugin-v1.0.0.zip\u003c/code\u003e（kintone へアップロードするプラグイン本体）\u003c/li\u003e\n\u003cli data-sourcepos=\"53:1-53:102\"\u003e\n\u003ccode\u003erelease/ksql-app-template-v1.0.0.zip\u003c/code\u003e（ksql プラグインの専用アプリテンプレート）\u003c/li\u003e\n\u003cli data-sourcepos=\"54:1-55:0\"\u003e\n\u003ccode\u003erelease/README.txt\u003c/code\u003e（同梱物の説明）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"56:1-56:48\"\u003e初回セットアップは次の流れです。\u003c/p\u003e\n\u003col data-sourcepos=\"58:1-61:0\"\u003e\n\u003cli data-sourcepos=\"58:1-58:74\"\u003ekintone のプラグイン画面で \u003ccode\u003eksql-plugin-*.zip\u003c/code\u003e を読み込む\u003c/li\u003e\n\u003cli data-sourcepos=\"59:1-59:77\"\u003e\n\u003ccode\u003eksql-app-template-*.zip\u003c/code\u003e を読み込んで専用アプリを作成する\u003c/li\u003e\n\u003cli data-sourcepos=\"60:1-61:0\"\u003e専用アプリはプラグイン設定済みテンプレートのため、作成後の追加設定は不要\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 data-sourcepos=\"62:1-62:40\"\u003e\n\u003cspan id=\"まずは-1-本実行式-select\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E3%81%AF-1-%E6%9C%AC%E5%AE%9F%E8%A1%8C%E5%BC%8F-select\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまずは 1 本実行（式 SELECT）\u003c/h2\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"64:1-66:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eksql \u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e https://example.cybozu.com \u003cspan class=\"nt\"\u003e-e\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"SELECT 'hello ksql' AS msg\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"68:1-68:44\"\u003e\n\u003cspan id=\"profile-必須の補足最小設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#profile-%E5%BF%85%E9%A0%88%E3%81%AE%E8%A3%9C%E8%B6%B3%E6%9C%80%E5%B0%8F%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eprofile 必須の補足（最小設定）\u003c/h2\u003e\n\u003cul data-sourcepos=\"70:1-73:0\"\u003e\n\u003cli data-sourcepos=\"70:1-70:115\"\u003eCLI は起動時に \u003ccode\u003edefaultProfile\u003c/code\u003e を解決するため、profile には最低限 \u003ccode\u003ebaseUrl\u003c/code\u003e が必要です。\u003c/li\u003e\n\u003cli data-sourcepos=\"71:1-71:97\"\u003e設定ファイルを使わない場合は、上のように \u003ccode\u003e--base-url\u003c/code\u003e を指定します。\u003c/li\u003e\n\u003cli data-sourcepos=\"72:1-73:0\"\u003e設定ファイルを使う場合は、カレントディレクトリの \u003ccode\u003e./ksql.config.json\u003c/code\u003e に保存します。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"74:1-74:39\"\u003e最小構成の \u003ccode\u003eksql.config.json\u003c/code\u003e 例:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"json\" data-sourcepos=\"76:1-85:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"defaultProfile\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"dev\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"profiles\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"dev\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"baseUrl\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"https://example.cybozu.com\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"87:1-87:53\"\u003e確認用（\u003ccode\u003euser/pass\u003c/code\u003e）の \u003ccode\u003eksql.config.json\u003c/code\u003e 例:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"json\" data-sourcepos=\"89:1-101:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"defaultProfile\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"dev-userpass\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"profiles\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"dev-userpass\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"baseUrl\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"https://example.cybozu.com\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"auth\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"userpass\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"username\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"your-user\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"password\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"env:KSQL_PASSWORD\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"103:1-106:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"nb\"\u003eexport \u003c/span\u003e\u003cspan class=\"nv\"\u003eKSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e'your-pass'\u003c/span\u003e\nksql \u003cspan class=\"nt\"\u003e-e\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"SELECT 'hello ksql' AS msg\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"powershell\" data-sourcepos=\"108:1-111:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"nv\"\u003e$\u003c/span\u003e\u003cspan class=\"nn\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"nv\"\u003eKSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"your-pass\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003cspan class=\"n\"\u003eksql\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e-e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"SELECT 'hello ksql' AS msg\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"113:1-113:41\"\u003e\n\u003cspan id=\"kintone-接続して実行select\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone-%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%A6%E5%AE%9F%E8%A1%8Cselect\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone 接続して実行（SELECT）\u003c/h2\u003e\n\u003cp data-sourcepos=\"115:1-115:30\"\u003e以下は bash の例です。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"117:1-122:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eksql \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e https://example.cybozu.com \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--token\u003c/span\u003e YOUR_API_TOKEN \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e-e\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"SELECT * FROM APP100 LIMIT 5\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"124:1-124:53\"\u003ePowerShell の場合は 1 行で実行できます。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"powershell\" data-sourcepos=\"126:1-128:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eksql\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ehttps://example.cybozu.com\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e--token\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eYOUR_API_TOKEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e-e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"SELECT * FROM APP100 LIMIT 5\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"130:1-130:35\"\u003eConsole 接続例（\u003ccode\u003euser/pass\u003c/code\u003e）:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"132:1-135:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"nb\"\u003eexport \u003c/span\u003e\u003cspan class=\"nv\"\u003eKSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e'your-password'\u003c/span\u003e\nksql \u003cspan class=\"nt\"\u003e--console\u003c/span\u003e \u003cspan class=\"nt\"\u003e--username\u003c/span\u003e your-username \u003cspan class=\"nt\"\u003e--password\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"\u003c/span\u003e\u003cspan class=\"nv\"\u003e$KSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"s2\"\u003e\"\u003c/span\u003e \u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e https://example.cybozu.com/\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"137:1-137:55\"\u003ePowerShell 例（環境変数で password を渡す）:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"powershell\" data-sourcepos=\"139:1-142:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"nv\"\u003e$\u003c/span\u003e\u003cspan class=\"nn\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"nv\"\u003eKSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"your-password\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003cspan class=\"n\"\u003eksql\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e--console\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e--username\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eyour-username\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e--password\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nv\"\u003e$\u003c/span\u003e\u003cspan class=\"nn\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"nv\"\u003eKSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ehttps://example.cybozu.com/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"144:1-144:32\"\u003e少し実践的な例（JOIN）:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"146:1-160:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\n  \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e会社名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e商談フェーズ\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e売上\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4148\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\n\u003cspan class=\"k\"\u003eINNER\u003c/span\u003e \u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4149\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\n  \u003cspan class=\"k\"\u003eON\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e商談フェーズ\u003c/span\u003e \u003cspan class=\"k\"\u003eIN\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e'提案中'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e'内示'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e'受注'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e \u003cspan class=\"mi\"\u003e50\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"162:1-162:53\"\u003e\n\u003cspan id=\"appprofile-で環境を切り替えるcli\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#appprofile-%E3%81%A7%E7%92%B0%E5%A2%83%E3%82%92%E5%88%87%E3%82%8A%E6%9B%BF%E3%81%88%E3%82%8Bcli\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003eAPP@profile\u003c/code\u003e で環境を切り替える（CLI）\u003c/h2\u003e\n\u003cp data-sourcepos=\"164:1-164:104\"\u003e\u003ccode\u003eAPP@profile\u003c/code\u003e を使うと、SQL 内で APP ごとに接続先プロファイルを指定できます。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"166:1-169:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4148\u003c/span\u003e\u003cspan class=\"o\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003edev\u003c/span\u003e \u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4149\u003c/span\u003e\u003cspan class=\"o\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eguest\u003c/span\u003e \u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"171:1-171:26\"\u003e\u003ccode\u003eksql.config.json\u003c/code\u003e の例:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"json\" data-sourcepos=\"173:1-194:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"defaultProfile\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"dev\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"profiles\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"dev\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"baseUrl\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"https://example.cybozu.com\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"auth\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"token\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"tokenMap\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n        \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"APP4148\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"env:KSQL_TOKEN_DEV_4148\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"guest\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"baseUrl\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"https://example.cybozu.com\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"guestSpaceId\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"auth\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"token\"\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"tokenMap\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n        \u003c/span\u003e\u003cspan class=\"nl\"\u003e\"APP4149\"\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"env:KSQL_TOKEN_GUEST_4149\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n      \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n  \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"196:1-196:40\"\u003e\n\u003cspan id=\"dml-は安全ガード付きで実行\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#dml-%E3%81%AF%E5%AE%89%E5%85%A8%E3%82%AC%E3%83%BC%E3%83%89%E4%BB%98%E3%81%8D%E3%81%A7%E5%AE%9F%E8%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eDML は安全ガード付きで実行\u003c/h2\u003e\n\u003cp data-sourcepos=\"198:1-198:64\"\u003eDML は明示的に有効化しないと実行されません。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"200:1-206:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eksql \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e https://example.cybozu.com \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--token\u003c/span\u003e YOUR_API_TOKEN \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--allow-dml\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e-e\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"UPDATE APP100 SET 状態 = '完了' WHERE ステータス = '未着手'\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"208:1-208:111\"\u003e必要に応じて \u003ccode\u003e--dry-run\u003c/code\u003e や \u003ccode\u003eEXPLAIN\u003c/code\u003e と組み合わせると、変更前確認がしやすいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"210:1-210:15\"\u003e\n\u003cspan id=\"出力形式\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%87%BA%E5%8A%9B%E5%BD%A2%E5%BC%8F\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e出力形式\u003c/h2\u003e\n\u003cp data-sourcepos=\"212:1-212:78\"\u003eCLI は \u003ccode\u003etable / json / jsonl / csv / markdown\u003c/code\u003e 形式で出力できます。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"214:1-221:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eksql \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--base-url\u003c/span\u003e https://example.cybozu.com \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--token\u003c/span\u003e YOUR_API_TOKEN \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--format\u003c/span\u003e csv \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e--output\u003c/span\u003e ./out/customers.csv \u003cspan class=\"se\"\u003e\\\u003c/span\u003e\n  \u003cspan class=\"nt\"\u003e-e\u003c/span\u003e \u003cspan class=\"s2\"\u003e\"SELECT * FROM APP4148 LIMIT 100\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"223:1-223:33\"\u003e\n\u003cspan id=\"使い分けcli--plugin\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91cli--plugin\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e使い分け（CLI / Plugin）\u003c/h2\u003e\n\u003cp data-sourcepos=\"225:1-225:32\"\u003eCLI が向いているケース:\u003c/p\u003e\n\u003cul data-sourcepos=\"227:1-231:0\"\u003e\n\u003cli data-sourcepos=\"227:1-227:17\"\u003eバッチ処理\u003c/li\u003e\n\u003cli data-sourcepos=\"228:1-228:14\"\u003eCI/CD 連携\u003c/li\u003e\n\u003cli data-sourcepos=\"229:1-229:40\"\u003e\n\u003ccode\u003eAPP@profile\u003c/code\u003e を使った環境切替\u003c/li\u003e\n\u003cli data-sourcepos=\"230:1-231:0\"\u003e\n\u003ccode\u003eEXPLAIN\u003c/code\u003e や \u003ccode\u003e--dry-run\u003c/code\u003e を使った事前確認\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"232:1-232:35\"\u003ePlugin が向いているケース:\u003c/p\u003e\n\u003cul data-sourcepos=\"234:1-237:0\"\u003e\n\u003cli data-sourcepos=\"234:1-234:49\"\u003ekintone 画面内で対話的に操作したい\u003c/li\u003e\n\u003cli data-sourcepos=\"235:1-235:32\"\u003e非エンジニア向け運用\u003c/li\u003e\n\u003cli data-sourcepos=\"236:1-237:0\"\u003eUI で結果を確認しながら使いたい\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"238:1-238:21\"\u003e\n\u003cspan id=\"ハマりどころ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%8F%E3%83%9E%E3%82%8A%E3%81%A9%E3%81%93%E3%82%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eハマりどころ\u003c/h2\u003e\n\u003cul data-sourcepos=\"240:1-244:0\"\u003e\n\u003cli data-sourcepos=\"240:1-240:55\"\u003e\n\u003ccode\u003eFROM\u003c/code\u003e ありクエリでは \u003ccode\u003eAPPxxx\u003c/code\u003e 指定が必要\u003c/li\u003e\n\u003cli data-sourcepos=\"241:1-241:45\"\u003e\n\u003ccode\u003etokenMap\u003c/code\u003e は APP ごとに設定が必要\u003c/li\u003e\n\u003cli data-sourcepos=\"242:1-242:71\"\u003e\n\u003ccode\u003eunknown field code\u003c/code\u003e が出たらフィールドコード名を確認\u003c/li\u003e\n\u003cli data-sourcepos=\"243:1-244:0\"\u003e\n\u003ccode\u003eDELETE\u003c/code\u003e の \u003ccode\u003e@profile\u003c/code\u003e は現時点で未対応\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"245:1-245:12\"\u003e\n\u003cspan id=\"まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまとめ\u003c/h2\u003e\n\u003cp data-sourcepos=\"247:1-247:54\"\u003e最初は次の順で試すのがおすすめです。\u003c/p\u003e\n\u003col data-sourcepos=\"249:1-253:0\"\u003e\n\u003cli data-sourcepos=\"249:1-249:72\"\u003e\n\u003ccode\u003eSELECT 'hello ksql' AS msg\u003c/code\u003e（式 SELECT で基本動作を確認）\u003c/li\u003e\n\u003cli data-sourcepos=\"250:1-250:21\"\u003e1 アプリ SELECT\u003c/li\u003e\n\u003cli data-sourcepos=\"251:1-251:28\"\u003eJOIN / エクスポート\u003c/li\u003e\n\u003cli data-sourcepos=\"252:1-253:0\"\u003e\n\u003ccode\u003eAPP@profile\u003c/code\u003e / DML\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr data-sourcepos=\"254:1-254:3\"\u003e\n","body":"kintone を SQL ライクに扱える `kintone-sql-tools` を作成したので紹介します\n\nリポジトリ:\n\n- https://github.com/rex0220/kintone-sql-tools\n\n関連記事\n\n- [rex0220 kSQL プラグイン](https://qiita.com/rex0220/items/ed9e101cb28b0ed40869)\n- [rex0220 kSQL 言語リファレンス](https://qiita.com/rex0220/items/e089fddf4229d74be699)\n\n## はじめに\n\nkintone のデータ確認や抽出をするとき、\n「一覧を作るほどではないけど、条件を少し指定して取りたい」\nという場面は多いと思います。\n\n`kintone-sql-tools` は、kintone アプリを SQL 風の構文で扱えるツールセットです。\n\n- CLI（`ksql`）\n- kintone プラグイン（UI）\n\nの 2 つを用意していて、用途に応じて使い分けできます。\n\n## できること\n\n主な対応機能は次のとおりです。\n\n- `SELECT`（JOIN / GROUP BY / HAVING / CTE / UNION）\n- `EXPLAIN`\n- `INSERT` / `UPDATE` / `UPSERT` / `DELETE`（`--allow-dml` 必須）\n- サブテーブル仮想テーブル（`APP100$明細`）\n- CLI 拡張 `APP@profile`（環境切替）\n\n## 前提条件\n\n- Node.js 18 以上（CLI 利用時）\n- kintone 環境と対象アプリ\n- API トークン（CLI で token 認証を使う場合）\n\n## CLI のインストール\n\n```bash\nnpm install -g @rex0220/kintone-sql-tools\nksql --help\n```\n\n## kintone プラグイン（UI）の場所\n\nプラグイン版はリポジトリの `release` フォルダに配置しています。\n\n- `release/ksql-plugin-v1.0.0.zip`（kintone へアップロードするプラグイン本体）\n- `release/ksql-app-template-v1.0.0.zip`（ksql プラグインの専用アプリテンプレート）\n- `release/README.txt`（同梱物の説明）\n\n初回セットアップは次の流れです。\n\n1. kintone のプラグイン画面で `ksql-plugin-*.zip` を読み込む\n2. `ksql-app-template-*.zip` を読み込んで専用アプリを作成する\n3. 専用アプリはプラグイン設定済みテンプレートのため、作成後の追加設定は不要\n\n## まずは 1 本実行（式 SELECT）\n\n```bash\nksql --base-url https://example.cybozu.com -e \"SELECT 'hello ksql' AS msg\"\n```\n\n## profile 必須の補足（最小設定）\n\n- CLI は起動時に `defaultProfile` を解決するため、profile には最低限 `baseUrl` が必要です。\n- 設定ファイルを使わない場合は、上のように `--base-url` を指定します。\n- 設定ファイルを使う場合は、カレントディレクトリの `./ksql.config.json` に保存します。\n\n最小構成の `ksql.config.json` 例:\n\n```json\n{\n  \"defaultProfile\": \"dev\",\n  \"profiles\": {\n    \"dev\": {\n      \"baseUrl\": \"https://example.cybozu.com\"\n    }\n  }\n}\n```\n\n確認用（`user/pass`）の `ksql.config.json` 例:\n\n```json\n{\n  \"defaultProfile\": \"dev-userpass\",\n  \"profiles\": {\n    \"dev-userpass\": {\n      \"baseUrl\": \"https://example.cybozu.com\",\n      \"auth\": \"userpass\",\n      \"username\": \"your-user\",\n      \"password\": \"env:KSQL_PASSWORD\"\n    }\n  }\n}\n```\n\n```bash\nexport KSQL_PASSWORD='your-pass'\nksql -e \"SELECT 'hello ksql' AS msg\"\n```\n\n```powershell\n$env:KSQL_PASSWORD = \"your-pass\"\nksql -e \"SELECT 'hello ksql' AS msg\"\n```\n\n## kintone 接続して実行（SELECT）\n\n以下は bash の例です。\n\n```bash\nksql \\\n  --base-url https://example.cybozu.com \\\n  --token YOUR_API_TOKEN \\\n  -e \"SELECT * FROM APP100 LIMIT 5\"\n```\n\nPowerShell の場合は 1 行で実行できます。\n\n```powershell\nksql --base-url https://example.cybozu.com --token YOUR_API_TOKEN -e \"SELECT * FROM APP100 LIMIT 5\"\n```\n\nConsole 接続例（`user/pass`）:\n\n```bash\nexport KSQL_PASSWORD='your-password'\nksql --console --username your-username --password \"$KSQL_PASSWORD\" --base-url https://example.cybozu.com/\n```\n\nPowerShell 例（環境変数で password を渡す）:\n\n```powershell\n$env:KSQL_PASSWORD = \"your-password\"\nksql --console --username your-username --password $env:KSQL_PASSWORD --base-url https://example.cybozu.com/\n```\n\n少し実践的な例（JOIN）:\n\n```sql\nSELECT\n  a.顧客No,\n  a.会社名,\n  b.案件No_ AS 案件No,\n  b.案件名,\n  b.商談フェーズ,\n  b.売上\nFROM APP4148 AS a\nINNER JOIN APP4149 AS b\n  ON a.顧客No = b.顧客No_\nWHERE b.商談フェーズ IN ('提案中', '内示', '受注')\nORDER BY b.案件No_ DESC\nLIMIT 50;\n```\n\n## `APP@profile` で環境を切り替える（CLI）\n\n`APP@profile` を使うと、SQL 内で APP ごとに接続先プロファイルを指定できます。\n\n```sql\nSELECT * FROM APP4148@dev LIMIT 10;\nSELECT * FROM APP4149@guest LIMIT 10;\n```\n\n`ksql.config.json` の例:\n\n```json\n{\n  \"defaultProfile\": \"dev\",\n  \"profiles\": {\n    \"dev\": {\n      \"baseUrl\": \"https://example.cybozu.com\",\n      \"auth\": \"token\",\n      \"tokenMap\": {\n        \"APP4148\": \"env:KSQL_TOKEN_DEV_4148\"\n      }\n    },\n    \"guest\": {\n      \"baseUrl\": \"https://example.cybozu.com\",\n      \"guestSpaceId\": 1,\n      \"auth\": \"token\",\n      \"tokenMap\": {\n        \"APP4149\": \"env:KSQL_TOKEN_GUEST_4149\"\n      }\n    }\n  }\n}\n```\n\n## DML は安全ガード付きで実行\n\nDML は明示的に有効化しないと実行されません。\n\n```bash\nksql \\\n  --base-url https://example.cybozu.com \\\n  --token YOUR_API_TOKEN \\\n  --allow-dml \\\n  -e \"UPDATE APP100 SET 状態 = '完了' WHERE ステータス = '未着手'\"\n```\n\n必要に応じて `--dry-run` や `EXPLAIN` と組み合わせると、変更前確認がしやすいです。\n\n## 出力形式\n\nCLI は `table / json / jsonl / csv / markdown` 形式で出力できます。\n\n```bash\nksql \\\n  --base-url https://example.cybozu.com \\\n  --token YOUR_API_TOKEN \\\n  --format csv \\\n  --output ./out/customers.csv \\\n  -e \"SELECT * FROM APP4148 LIMIT 100\"\n```\n\n## 使い分け（CLI / Plugin）\n\nCLI が向いているケース:\n\n- バッチ処理\n- CI/CD 連携\n- `APP@profile` を使った環境切替\n- `EXPLAIN` や `--dry-run` を使った事前確認\n\nPlugin が向いているケース:\n\n- kintone 画面内で対話的に操作したい\n- 非エンジニア向け運用\n- UI で結果を確認しながら使いたい\n\n## ハマりどころ\n\n- `FROM` ありクエリでは `APPxxx` 指定が必要\n- `tokenMap` は APP ごとに設定が必要\n- `unknown field code` が出たらフィールドコード名を確認\n- `DELETE` の `@profile` は現時点で未対応\n\n## まとめ\n\n最初は次の順で試すのがおすすめです。\n\n1. `SELECT 'hello ksql' AS msg`（式 SELECT で基本動作を確認）\n2. 1 アプリ SELECT\n3. JOIN / エクスポート\n4. `APP@profile` / DML\n\n---\n","coediting":false,"comments_count":0,"created_at":"2026-04-09T14:38:27+09:00","group":null,"id":"42767e9d47afd5116253","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"SQL","versions":[]},{"name":"npm","versions":[]},{"name":"kintone","versions":[]}],"title":"rex0220 kintone-sql-tools のご紹介","updated_at":"2026-04-09T14:45:44+09:00","url":"https://qiita.com/rex0220/items/42767e9d47afd5116253","user":{"description":"","facebook_id":"","followees_count":0,"followers_count":150,"github_login_name":"rex0220","id":"rex0220","items_count":594,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":100572,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/100572/profile-images/1473708137","team_only":false,"twitter_screen_name":"rex02201","website_url":"https://rex0220.stores.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003ch2 data-sourcepos=\"1:1-1:15\"\u003e\n\u003cspan id=\"はじめに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eはじめに\u003c/h2\u003e\n\u003cp data-sourcepos=\"2:1-3:51\"\u003eこんにちは。\u003cbr\u003e\n業務改善エンジニアのこめまるです。\u003c/p\u003e\n\u003cp data-sourcepos=\"5:1-5:168\"\u003e今回は、kintoneでJavaScriptカスタマイズを書いたときに、\u003cstrong\u003e既存のプラグインが思った以上に邪魔をしてきた\u003c/strong\u003e話をまとめます。\u003c/p\u003e\n\u003cp data-sourcepos=\"7:1-7:100\"\u003ekintoneは手軽にカスタマイズできるのが魅力ですが、実際に触ってみると、\u003c/p\u003e\n\u003cul data-sourcepos=\"9:1-13:0\"\u003e\n\u003cli data-sourcepos=\"9:1-9:37\"\u003e自分で書いたJSが効かない\u003c/li\u003e\n\u003cli data-sourcepos=\"10:1-10:65\"\u003eさっきまで動いていた処理が急におかしくなる\u003c/li\u003e\n\u003cli data-sourcepos=\"11:1-11:45\"\u003econsole上ではエラーが見えにくい\u003c/li\u003e\n\u003cli data-sourcepos=\"12:1-13:0\"\u003e原因が自作JSなのかプラグインなのか切り分けしづらい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"14:1-14:48\"\u003eということがけっこう起こります。\u003c/p\u003e\n\u003cp data-sourcepos=\"16:1-16:153\"\u003e特に、\u003cstrong\u003eすでに何らかのプラグインが入っているアプリに後からJSを足す\u003c/strong\u003e場合は、想像以上にハマりやすいです。\u003c/p\u003e\n\u003cdiv data-sourcepos=\"18:1-26:3\" class=\"note info\"\u003e\n\u003cspan class=\"fa fa-fw fa-check-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"19:1-19:42\"\u003eこの記事はこんな人におすすめ\u003c/p\u003e\n\u003cul data-sourcepos=\"21:1-25:0\"\u003e\n\u003cli data-sourcepos=\"21:1-21:61\"\u003ekintoneでJavaScriptカスタマイズを書いている方\u003c/li\u003e\n\u003cli data-sourcepos=\"22:1-22:106\"\u003e「JSを書いたのに動かない」「なんか変な挙動になる」で困ったことがある方\u003c/li\u003e\n\u003cli data-sourcepos=\"23:1-23:68\"\u003eプラグインとカスタマイズの競合を疑っている方\u003c/li\u003e\n\u003cli data-sourcepos=\"24:1-25:0\"\u003e困ったときの切り分け方や解決の進め方を知りたい方\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp data-sourcepos=\"28:1-28:179\"\u003eこの記事では、\u003cstrong\u003e実際に困りがちなポイント\u003c/strong\u003eと、\u003cstrong\u003eどうやって原因を切り分けて、どう解決していくか\u003c/strong\u003eを整理して書いていきます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"31:1-31:15\"\u003e\n\u003cspan id=\"先に結論\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%85%88%E3%81%AB%E7%B5%90%E8%AB%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e先に結論\u003c/h2\u003e\n\u003cp data-sourcepos=\"33:1-33:145\"\u003e最初に結論を書くと、kintoneでJSがうまく動かないときは、\u003cstrong\u003e自分のコード単体で考えないほうがよい\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp data-sourcepos=\"35:1-35:105\"\u003e特に以下のような状況なら、プラグイン競合をかなり疑ったほうがよいです。\u003c/p\u003e\n\u003cul data-sourcepos=\"37:1-41:0\"\u003e\n\u003cli data-sourcepos=\"37:1-37:41\"\u003e同じフィールドを触っている\u003c/li\u003e\n\u003cli data-sourcepos=\"38:1-38:56\"\u003e同じ画面表示タイミングで処理している\u003c/li\u003e\n\u003cli data-sourcepos=\"39:1-39:46\"\u003eDOMを直接触る系のJSを書いている\u003c/li\u003e\n\u003cli data-sourcepos=\"40:1-41:0\"\u003e入力制御系・表示制御系・一覧拡張系のプラグインが入っている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"42:1-42:12\"\u003eつまり、\u003c/p\u003e\n\u003cdiv data-sourcepos=\"44:1-47:3\" class=\"note warn\"\u003e\n\u003cspan class=\"fa fa-fw fa-exclamation-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"45:1-46:82\"\u003e\u003cstrong\u003e「自作JSがバグっている」のではなく、\u003cbr\u003e\n「プラグインと自作JSが同じ場所を触ってぶつかっている」\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp data-sourcepos=\"49:1-49:45\"\u003eというケースが普通にあります。\u003c/p\u003e\n\u003cp data-sourcepos=\"51:1-51:36\"\u003eなので、困ったときはまず\u003c/p\u003e\n\u003cul data-sourcepos=\"53:1-57:0\"\u003e\n\u003cli data-sourcepos=\"53:1-53:26\"\u003eプラグインを疑う\u003c/li\u003e\n\u003cli data-sourcepos=\"54:1-54:32\"\u003e影響範囲を切り分ける\u003c/li\u003e\n\u003cli data-sourcepos=\"55:1-55:23\"\u003eDOM依存を減らす\u003c/li\u003e\n\u003cli data-sourcepos=\"56:1-57:0\"\u003eイベントやフィールド操作の責任を整理する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"58:1-58:63\"\u003eこの順で見ていくと、かなり進めやすいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"61:1-61:45\"\u003e\n\u003cspan id=\"どういうときに起こりやすいか\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E3%81%A8%E3%81%8D%E3%81%AB%E8%B5%B7%E3%81%93%E3%82%8A%E3%82%84%E3%81%99%E3%81%84%E3%81%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eどういうときに起こりやすいか\u003c/h2\u003e\n\u003cp data-sourcepos=\"63:1-63:106\"\u003ekintoneで競合っぽい問題が起きやすいのは、だいたい以下のようなケースです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"65:1-65:67\"\u003e\n\u003cspan id=\"1-同じフィールドを複数の仕組みが触っている\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E5%90%8C%E3%81%98%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%92%E8%A4%87%E6%95%B0%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF%E3%81%8C%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. 同じフィールドを複数の仕組みが触っている\u003c/h3\u003e\n\u003cp data-sourcepos=\"67:1-67:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"69:1-73:0\"\u003e\n\u003cli data-sourcepos=\"69:1-69:77\"\u003eプラグインがフィールドの表示・非表示を制御している\u003c/li\u003e\n\u003cli data-sourcepos=\"70:1-70:70\"\u003e自作JSでも同じフィールドを表示・非表示している\u003c/li\u003e\n\u003cli data-sourcepos=\"71:1-71:50\"\u003eプラグインが値を自動設定している\u003c/li\u003e\n\u003cli data-sourcepos=\"72:1-73:0\"\u003e自作JSでも同じ値を書き換えている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"74:1-74:30\"\u003eといったケースです。\u003c/p\u003e\n\u003cp data-sourcepos=\"76:1-76:118\"\u003eこの状態になると、\u003cstrong\u003eどちらが最後に効くのか\u003c/strong\u003eという話になりやすく、見た目としては\u003c/p\u003e\n\u003cul data-sourcepos=\"78:1-81:0\"\u003e\n\u003cli data-sourcepos=\"78:1-78:38\"\u003e一瞬表示されてすぐ消える\u003c/li\u003e\n\u003cli data-sourcepos=\"79:1-79:38\"\u003e値が入ったと思ったら戻る\u003c/li\u003e\n\u003cli data-sourcepos=\"80:1-81:0\"\u003e編集できるはずが編集できない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"82:1-82:66\"\u003eのような、かなり分かりづらい症状になります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"85:1-85:34\"\u003e\n\u003cspan id=\"2-domを直接触っている\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-dom%E3%82%92%E7%9B%B4%E6%8E%A5%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. DOMを直接触っている\u003c/h3\u003e\n\u003cp data-sourcepos=\"87:1-87:45\"\u003eこれはかなりハマりやすいです。\u003c/p\u003e\n\u003cp data-sourcepos=\"89:1-89:40\"\u003ekintoneカスタマイズでは、つい\u003c/p\u003e\n\u003cul data-sourcepos=\"91:1-95:0\"\u003e\n\u003cli data-sourcepos=\"91:1-91:40\"\u003e特定のclassを探して何かする\u003c/li\u003e\n\u003cli data-sourcepos=\"92:1-92:32\"\u003eボタンの位置を変える\u003c/li\u003e\n\u003cli data-sourcepos=\"93:1-93:35\"\u003e画面上の要素を直接隠す\u003c/li\u003e\n\u003cli data-sourcepos=\"94:1-95:0\"\u003eラベルや並び順を見た目ベースでいじる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"96:1-96:48\"\u003eみたいなことをやりたくなります。\u003c/p\u003e\n\u003cp data-sourcepos=\"98:1-98:111\"\u003eただ、プラグイン側も同じようにDOMを触っていると、かなりぶつかりやすいです。\u003c/p\u003e\n\u003cp data-sourcepos=\"100:1-100:36\"\u003eしかも、DOMを直接触る系は\u003c/p\u003e\n\u003cul data-sourcepos=\"102:1-105:0\"\u003e\n\u003cli data-sourcepos=\"102:1-102:32\"\u003e画面構造の変化に弱い\u003c/li\u003e\n\u003cli data-sourcepos=\"103:1-103:44\"\u003eプラグインの描画後処理に弱い\u003c/li\u003e\n\u003cli data-sourcepos=\"104:1-105:0\"\u003ePC画面とモバイル画面で差が出やすい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"106:1-106:75\"\u003eという問題もあるので、競合の温床になりやすいです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"109:1-109:70\"\u003e\n\u003cspan id=\"3-一覧画面詳細画面編集画面で前提がズレる\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E4%B8%80%E8%A6%A7%E7%94%BB%E9%9D%A2%E8%A9%B3%E7%B4%B0%E7%94%BB%E9%9D%A2%E7%B7%A8%E9%9B%86%E7%94%BB%E9%9D%A2%E3%81%A7%E5%89%8D%E6%8F%90%E3%81%8C%E3%82%BA%E3%83%AC%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. 一覧画面・詳細画面・編集画面で前提がズレる\u003c/h3\u003e\n\u003cp data-sourcepos=\"111:1-111:24\"\u003e同じアプリでも、\u003c/p\u003e\n\u003cul data-sourcepos=\"113:1-117:0\"\u003e\n\u003cli data-sourcepos=\"113:1-113:8\"\u003e一覧\u003c/li\u003e\n\u003cli data-sourcepos=\"114:1-114:8\"\u003e詳細\u003c/li\u003e\n\u003cli data-sourcepos=\"115:1-115:14\"\u003e新規作成\u003c/li\u003e\n\u003cli data-sourcepos=\"116:1-117:0\"\u003e編集\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"118:1-118:45\"\u003eで画面の状態はかなり違います。\u003c/p\u003e\n\u003cp data-sourcepos=\"120:1-120:60\"\u003eここにプラグインも絡んでくると、たとえば\u003c/p\u003e\n\u003cul data-sourcepos=\"122:1-125:0\"\u003e\n\u003cli data-sourcepos=\"122:1-122:50\"\u003e一覧では動くのに詳細では動かない\u003c/li\u003e\n\u003cli data-sourcepos=\"123:1-123:32\"\u003e新規作成だけ変になる\u003c/li\u003e\n\u003cli data-sourcepos=\"124:1-125:0\"\u003e編集画面だけ項目が消える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"126:1-126:36\"\u003eみたいなことが起きます。\u003c/p\u003e\n\u003cp data-sourcepos=\"128:1-129:91\"\u003eこのとき「たまたまその画面でバグる」のではなく、\u003cbr\u003e\n\u003cstrong\u003eその画面だけプラグインの影響が強く出ている\u003c/strong\u003eこともあります。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"132:1-132:27\"\u003e\n\u003cspan id=\"実際に困ったこと\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E9%9A%9B%E3%81%AB%E5%9B%B0%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実際に困ったこと\u003c/h2\u003e\n\u003cp data-sourcepos=\"134:1-134:96\"\u003eここからは、実際に起きがちな「困ったこと」をパターンで書きます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"136:1-136:62\"\u003e\n\u003cspan id=\"1-jsで値を入れてもあとから別の値に戻る\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-js%E3%81%A7%E5%80%A4%E3%82%92%E5%85%A5%E3%82%8C%E3%81%A6%E3%82%82%E3%81%82%E3%81%A8%E3%81%8B%E3%82%89%E5%88%A5%E3%81%AE%E5%80%A4%E3%81%AB%E6%88%BB%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. JSで値を入れても、あとから別の値に戻る\u003c/h2\u003e\n\u003cp data-sourcepos=\"138:1-138:33\"\u003eこれはかなり典型です。\u003c/p\u003e\n\u003cp data-sourcepos=\"140:1-140:143\"\u003eたとえば、自作JSであるフィールドに値をセットしたのに、画面を見ると別の値になっているケースです。\u003c/p\u003e\n\u003cp data-sourcepos=\"142:1-142:105\"\u003e最初は「自分の代入処理が間違っているのかな」と思いがちですが、実際には\u003c/p\u003e\n\u003cul data-sourcepos=\"144:1-147:0\"\u003e\n\u003cli data-sourcepos=\"144:1-144:68\"\u003eプラグイン側でも同じフィールドを更新している\u003c/li\u003e\n\u003cli data-sourcepos=\"145:1-145:53\"\u003e別イベントで後から上書きされている\u003c/li\u003e\n\u003cli data-sourcepos=\"146:1-147:0\"\u003eフィールドの自動計算や変換処理が入っている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"148:1-148:33\"\u003eということがあります。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"150:1-150:25\"\u003e\n\u003cspan id=\"このときの見方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AE%E8%A6%8B%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eこのときの見方\u003c/h3\u003e\n\u003cul data-sourcepos=\"152:1-155:0\"\u003e\n\u003cli data-sourcepos=\"152:1-152:68\"\u003eどのフィールドが書き換わっているかを確認する\u003c/li\u003e\n\u003cli data-sourcepos=\"153:1-153:65\"\u003eそのフィールドを触るプラグインがないか見る\u003c/li\u003e\n\u003cli data-sourcepos=\"154:1-155:0\"\u003eイベント発火のたびに \u003ccode\u003econsole.log()\u003c/code\u003e で値を追う\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"156:1-156:13\"\u003e\n\u003cspan id=\"解決法\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E6%B3%95\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e解決法\u003c/h3\u003e\n\u003cul data-sourcepos=\"158:1-161:0\"\u003e\n\u003cli data-sourcepos=\"158:1-158:56\"\u003e同じフィールドを複数箇所で更新しない\u003c/li\u003e\n\u003cli data-sourcepos=\"159:1-159:85\"\u003e値設定の責任を「JS側」か「プラグイン側」どちらかに寄せる\u003c/li\u003e\n\u003cli data-sourcepos=\"160:1-161:0\"\u003eどうしても共存させるなら、対象フィールドを分ける\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv data-sourcepos=\"162:1-165:3\" class=\"note info\"\u003e\n\u003cspan class=\"fa fa-fw fa-check-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"163:1-164:54\"\u003e\u003cstrong\u003e1つのフィールドに複数のロジックを集めすぎない\u003c/strong\u003e\u003cbr\u003e\nこれだけでも、かなり事故が減ります。\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 data-sourcepos=\"168:1-168:66\"\u003e\n\u003cspan id=\"2-表示非表示の制御が思った通りにならない\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E8%A1%A8%E7%A4%BA%E9%9D%9E%E8%A1%A8%E7%A4%BA%E3%81%AE%E5%88%B6%E5%BE%A1%E3%81%8C%E6%80%9D%E3%81%A3%E3%81%9F%E9%80%9A%E3%82%8A%E3%81%AB%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. 表示・非表示の制御が思った通りにならない\u003c/h2\u003e\n\u003cp data-sourcepos=\"170:1-170:24\"\u003eこれも多いです。\u003c/p\u003e\n\u003cp data-sourcepos=\"172:1-172:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"174:1-177:0\"\u003e\n\u003cli data-sourcepos=\"174:1-174:49\"\u003eJSでは表示したはずなのに見えない\u003c/li\u003e\n\u003cli data-sourcepos=\"175:1-175:50\"\u003e一瞬表示されるけど、あとで消える\u003c/li\u003e\n\u003cli data-sourcepos=\"176:1-177:0\"\u003e条件によって出し分けたいのに固定される\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"178:1-178:27\"\u003eというケースです。\u003c/p\u003e\n\u003cp data-sourcepos=\"180:1-180:117\"\u003eこのときは、表示制御系のプラグインが同じフィールドを触っていることが多いです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"182:1-182:13\"\u003e\n\u003cspan id=\"解決法-1\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E6%B3%95-1\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e解決法\u003c/h3\u003e\n\u003cul data-sourcepos=\"184:1-188:0\"\u003e\n\u003cli data-sourcepos=\"184:1-184:101\"\u003eまず、そのフィールドの表示制御をプラグインが持っていないか確認する\u003c/li\u003e\n\u003cli data-sourcepos=\"185:1-185:48\"\u003e表示制御はなるべく1箇所に寄せる\u003c/li\u003e\n\u003cli data-sourcepos=\"186:1-186:79\"\u003eJSとプラグインで分担するなら、対象フィールドを分ける\u003c/li\u003e\n\u003cli data-sourcepos=\"187:1-188:0\"\u003eDOMの \u003ccode\u003edisplay:none\u003c/code\u003e ではなく、可能な範囲でkintone側の正式な操作に寄せる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"189:1-189:27\"\u003eここで大事なのは、\u003c/p\u003e\n\u003cdiv data-sourcepos=\"191:1-193:3\" class=\"note warn\"\u003e\n\u003cspan class=\"fa fa-fw fa-exclamation-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"192:1-192:90\"\u003e\u003cstrong\u003e見た目を隠す処理\u003c/strong\u003e と \u003cstrong\u003ekintoneとしての表示制御\u003c/strong\u003e は同じではない\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp data-sourcepos=\"195:1-195:24\"\u003eということです。\u003c/p\u003e\n\u003cp data-sourcepos=\"197:1-197:135\"\u003e画面上で消えたように見えても、裏で状態がズレていると、後で別の不具合につながりやすいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"200:1-200:62\"\u003e\n\u003cspan id=\"3-ボタンや追加uiが出たり出なかったりする\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%84%E8%BF%BD%E5%8A%A0ui%E3%81%8C%E5%87%BA%E3%81%9F%E3%82%8A%E5%87%BA%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%8A%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. ボタンや追加UIが出たり出なかったりする\u003c/h2\u003e\n\u003cp data-sourcepos=\"202:1-202:71\"\u003e自作JSでボタンやメッセージ領域を追加したときに、\u003c/p\u003e\n\u003cul data-sourcepos=\"204:1-208:0\"\u003e\n\u003cli data-sourcepos=\"204:1-204:41\"\u003e出る画面と出ない画面がある\u003c/li\u003e\n\u003cli data-sourcepos=\"205:1-205:38\"\u003eリロードすると二重に出る\u003c/li\u003e\n\u003cli data-sourcepos=\"206:1-206:20\"\u003e位置が崩れる\u003c/li\u003e\n\u003cli data-sourcepos=\"207:1-208:0\"\u003eプラグインのUIと重なる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"209:1-209:33\"\u003eということがあります。\u003c/p\u003e\n\u003cp data-sourcepos=\"211:1-211:111\"\u003eこれは、DOM追加のタイミングや、再描画のされ方が影響していることが多いです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"213:1-213:13\"\u003e\n\u003cspan id=\"解決法-2\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E6%B3%95-2\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e解決法\u003c/h3\u003e\n\u003cul data-sourcepos=\"215:1-219:0\"\u003e\n\u003cli data-sourcepos=\"215:1-215:56\"\u003e同じ要素を何度も追加しないようにする\u003c/li\u003e\n\u003cli data-sourcepos=\"216:1-216:50\"\u003e追加前に既存要素の存在確認をする\u003c/li\u003e\n\u003cli data-sourcepos=\"217:1-217:50\"\u003e画面ごとのイベントを分けて考える\u003c/li\u003e\n\u003cli data-sourcepos=\"218:1-219:0\"\u003eDOMの特定classに強く依存しすぎない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"220:1-221:86\"\u003eたとえば、ボタン追加処理は「毎回追加」ではなく、\u003cbr\u003e\n\u003cstrong\u003eなければ作る\u003c/strong\u003e くらいの作りにしておくと安定しやすいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"224:1-224:74\"\u003e\n\u003cspan id=\"4-プラグインを入れたら急に自作jsが効かなくなった\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%92%E5%85%A5%E3%82%8C%E3%81%9F%E3%82%89%E6%80%A5%E3%81%AB%E8%87%AA%E4%BD%9Cjs%E3%81%8C%E5%8A%B9%E3%81%8B%E3%81%AA%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4. プラグインを入れたら急に自作JSが効かなくなった\u003c/h2\u003e\n\u003cp data-sourcepos=\"226:1-226:48\"\u003eこれは一番わかりやすい症状です。\u003c/p\u003e\n\u003cp data-sourcepos=\"228:1-228:147\"\u003e「昨日までは動いていたのに、プラグインを入れたらダメになった」なら、かなり高確率で影響があります。\u003c/p\u003e\n\u003cp data-sourcepos=\"230:1-231:103\"\u003eただ、ここでありがちなのが、\u003cbr\u003e\n\u003cstrong\u003eプラグインが悪いのではなく、両方が同じ前提に立っている\u003c/strong\u003eケースです。\u003c/p\u003e\n\u003cp data-sourcepos=\"233:1-233:12\"\u003eつまり、\u003c/p\u003e\n\u003cul data-sourcepos=\"235:1-238:0\"\u003e\n\u003cli data-sourcepos=\"235:1-235:58\"\u003eどちらも同じ場所にUIを出そうとしている\u003c/li\u003e\n\u003cli data-sourcepos=\"236:1-236:78\"\u003eどちらも同じフィールドを必須/非必須っぽく扱っている\u003c/li\u003e\n\u003cli data-sourcepos=\"237:1-238:0\"\u003eどちらも同じイベントで動こうとしている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"239:1-239:24\"\u003eということです。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"241:1-241:13\"\u003e\n\u003cspan id=\"解決法-3\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E6%B3%95-3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e解決法\u003c/h3\u003e\n\u003cp data-sourcepos=\"243:1-243:63\"\u003eこの場合は、まず感情を捨てて切り分けます。\u003c/p\u003e\n\u003ch4 data-sourcepos=\"245:1-245:11\"\u003e\n\u003cspan id=\"手順\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%89%8B%E9%A0%86\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e手順\u003c/h4\u003e\n\u003col data-sourcepos=\"247:1-252:0\"\u003e\n\u003cli data-sourcepos=\"247:1-247:59\"\u003eプラグインを一時的に外して再確認する\u003c/li\u003e\n\u003cli data-sourcepos=\"248:1-248:64\"\u003e自作JSを外してプラグイン単体でも確認する\u003c/li\u003e\n\u003cli data-sourcepos=\"249:1-249:56\"\u003eどちらを入れたときに崩れるかを見る\u003c/li\u003e\n\u003cli data-sourcepos=\"250:1-250:41\"\u003e影響が出る画面を特定する\u003c/li\u003e\n\u003cli data-sourcepos=\"251:1-252:0\"\u003e触っているフィールドとイベントを洗い出す\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp data-sourcepos=\"253:1-253:57\"\u003eこれをやるだけで、だいぶ前に進みます。\u003c/p\u003e\n\u003cdiv data-sourcepos=\"255:1-258:3\" class=\"note info\"\u003e\n\u003cspan class=\"fa fa-fw fa-check-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"256:1-257:74\"\u003e「とりあえずコードを直す」の前に、\u003cbr\u003e\n\u003cstrong\u003e何と何がぶつかっているかを見つける\u003c/strong\u003e のが先です。\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 data-sourcepos=\"261:1-261:27\"\u003e\n\u003cspan id=\"切り分けのやり方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%88%87%E3%82%8A%E5%88%86%E3%81%91%E3%81%AE%E3%82%84%E3%82%8A%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e切り分けのやり方\u003c/h2\u003e\n\u003cp data-sourcepos=\"263:1-263:63\"\u003eここはかなり重要なので、手順でまとめます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"265:1-265:51\"\u003e\n\u003cspan id=\"1-まずはアプリを複製して検証する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E3%81%BE%E3%81%9A%E3%81%AF%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E8%A4%87%E8%A3%BD%E3%81%97%E3%81%A6%E6%A4%9C%E8%A8%BC%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. まずはアプリを複製して検証する\u003c/h2\u003e\n\u003cp data-sourcepos=\"267:1-267:102\"\u003e本番アプリや利用中アプリでそのまま試すと、余計に見えづらくなります。\u003c/p\u003e\n\u003cp data-sourcepos=\"269:1-269:48\"\u003eそのため、まずは複製したアプリで\u003c/p\u003e\n\u003cul data-sourcepos=\"271:1-275:0\"\u003e\n\u003cli data-sourcepos=\"271:1-271:23\"\u003eプラグインあり\u003c/li\u003e\n\u003cli data-sourcepos=\"272:1-272:23\"\u003eプラグインなし\u003c/li\u003e\n\u003cli data-sourcepos=\"273:1-273:16\"\u003e自作JSあり\u003c/li\u003e\n\u003cli data-sourcepos=\"274:1-275:0\"\u003e自作JSなし\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"276:1-276:54\"\u003eを試せる状態を作るのがおすすめです。\u003c/p\u003e\n\u003cp data-sourcepos=\"278:1-278:54\"\u003eこれだけで、かなり冷静に見られます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"281:1-281:48\"\u003e\n\u003cspan id=\"2-何の画面で起きるかを固定する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E4%BD%95%E3%81%AE%E7%94%BB%E9%9D%A2%E3%81%A7%E8%B5%B7%E3%81%8D%E3%82%8B%E3%81%8B%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. 何の画面で起きるかを固定する\u003c/h2\u003e\n\u003cp data-sourcepos=\"283:1-283:78\"\u003e「なんか変」と言っても、画面が違えば原因も違います。\u003c/p\u003e\n\u003cp data-sourcepos=\"285:1-285:48\"\u003eなので、まずは以下を固定します。\u003c/p\u003e\n\u003cul data-sourcepos=\"287:1-291:0\"\u003e\n\u003cli data-sourcepos=\"287:1-287:17\"\u003e一覧画面か\u003c/li\u003e\n\u003cli data-sourcepos=\"288:1-288:17\"\u003e詳細画面か\u003c/li\u003e\n\u003cli data-sourcepos=\"289:1-289:23\"\u003e新規作成画面か\u003c/li\u003e\n\u003cli data-sourcepos=\"290:1-291:0\"\u003e編集画面か\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"292:1-292:72\"\u003eこの整理をしないまま見ると、話が散りやすいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"295:1-295:51\"\u003e\n\u003cspan id=\"3-触っているフィールドを洗い出す\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%92%E6%B4%97%E3%81%84%E5%87%BA%E3%81%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. 触っているフィールドを洗い出す\u003c/h2\u003e\n\u003cp data-sourcepos=\"297:1-297:9\"\u003e次に、\u003c/p\u003e\n\u003cul data-sourcepos=\"299:1-301:0\"\u003e\n\u003cli data-sourcepos=\"299:1-299:43\"\u003e自作JSが触っているフィールド\u003c/li\u003e\n\u003cli data-sourcepos=\"300:1-301:0\"\u003eプラグインが触っていそうなフィールド\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"302:1-302:24\"\u003eを一覧にします。\u003c/p\u003e\n\u003cp data-sourcepos=\"304:1-304:51\"\u003eこれをやると、かなり見えてきます。\u003c/p\u003e\n\u003cp data-sourcepos=\"306:1-306:57\"\u003e特に、以下が重なっていたら要注意です。\u003c/p\u003e\n\u003cul data-sourcepos=\"308:1-313:0\"\u003e\n\u003cli data-sourcepos=\"308:1-308:20\"\u003e表示制御対象\u003c/li\u003e\n\u003cli data-sourcepos=\"309:1-309:26\"\u003e値の自動設定対象\u003c/li\u003e\n\u003cli data-sourcepos=\"310:1-310:44\"\u003e必須っぽい扱いをしている項目\u003c/li\u003e\n\u003cli data-sourcepos=\"311:1-313:0\"\u003e参照/計算に使っている項目\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"314:1-314:31\"\u003e\n\u003cspan id=\"4-consoleでログを出す\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-console%E3%81%A7%E3%83%AD%E3%82%B0%E3%82%92%E5%87%BA%E3%81%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4. consoleでログを出す\u003c/h2\u003e\n\u003cp data-sourcepos=\"316:1-316:36\"\u003eシンプルですが強いです。\u003c/p\u003e\n\u003cp data-sourcepos=\"318:1-318:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"320:1-323:0\"\u003e\n\u003cli data-sourcepos=\"320:1-320:47\"\u003eイベントが本当に発火しているか\u003c/li\u003e\n\u003cli data-sourcepos=\"321:1-321:29\"\u003eその時点の値が何か\u003c/li\u003e\n\u003cli data-sourcepos=\"322:1-323:0\"\u003eどの分岐に入ったか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"324:1-324:66\"\u003eをログで出すだけでも、かなり状況が見えます。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"javascript\" data-sourcepos=\"326:1-329:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e編集画面表示イベント\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nf\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"s1\"\u003e対象フィールドの値:\u003c/span\u003e\u003cspan class=\"dl\"\u003e'\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003erecord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esample_field\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"331:1-332:140\"\u003eこういうログを、要所だけでも入れておくと、\u003cbr\u003e\n「そもそも自分のJSが動いていないのか」「動いたあとで壊されているのか」が分かりやすくなります。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"335:1-335:21\"\u003e\n\u003cspan id=\"解決の考え方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E3%81%AE%E8%80%83%E3%81%88%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e解決の考え方\u003c/h2\u003e\n\u003cp data-sourcepos=\"337:1-337:105\"\u003eここからは、私が実際に「こう考えると直しやすい」と感じたポイントです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"339:1-339:24\"\u003e\n\u003cspan id=\"1-役割を分ける\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E5%BD%B9%E5%89%B2%E3%82%92%E5%88%86%E3%81%91%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. 役割を分ける\u003c/h2\u003e\n\u003cp data-sourcepos=\"341:1-341:36\"\u003e一番大事なのはこれです。\u003c/p\u003e\n\u003cul data-sourcepos=\"343:1-346:0\"\u003e\n\u003cli data-sourcepos=\"343:1-343:44\"\u003e表示制御はどっちが担当するか\u003c/li\u003e\n\u003cli data-sourcepos=\"344:1-344:41\"\u003e値設定はどっちが担当するか\u003c/li\u003e\n\u003cli data-sourcepos=\"345:1-346:0\"\u003eUI追加はどっちが担当するか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"347:1-347:36\"\u003eを曖昧にしないことです。\u003c/p\u003e\n\u003cp data-sourcepos=\"349:1-350:64\"\u003eプラグインと自作JSが共存するときは、\u003cbr\u003e\n\u003cstrong\u003e同じ責務を両方に持たせない\u003c/strong\u003eのが基本です。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"353:1-353:27\"\u003e\n\u003cspan id=\"2-dom操作を減らす\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-dom%E6%93%8D%E4%BD%9C%E3%82%92%E6%B8%9B%E3%82%89%E3%81%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. DOM操作を減らす\u003c/h2\u003e\n\u003cp data-sourcepos=\"355:1-356:99\"\u003ekintoneでは、見た目を直接いじるより、\u003cbr\u003e\nまずは「正式に触れる範囲」で解決できないか考えたほうが安定します。\u003c/p\u003e\n\u003cp data-sourcepos=\"358:1-359:81\"\u003eDOM直操作が必要な場面もありますが、\u003cbr\u003e\nそれをやるほどプラグインとの競合確率は上がる印象です。\u003c/p\u003e\n\u003cp data-sourcepos=\"361:1-361:12\"\u003eなので、\u003c/p\u003e\n\u003cul data-sourcepos=\"363:1-366:0\"\u003e\n\u003cli data-sourcepos=\"363:1-363:59\"\u003eまずはレコード値ベースで解決できないか\u003c/li\u003e\n\u003cli data-sourcepos=\"364:1-364:41\"\u003eフィールド制御で済まないか\u003c/li\u003e\n\u003cli data-sourcepos=\"365:1-366:0\"\u003eUI追加だけで済まないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"367:1-367:45\"\u003eを先に考えるのがおすすめです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"370:1-370:48\"\u003e\n\u003cspan id=\"3-スマートに直そうとしすぎない\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%81%AB%E7%9B%B4%E3%81%9D%E3%81%86%E3%81%A8%E3%81%97%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. スマートに直そうとしすぎない\u003c/h2\u003e\n\u003cp data-sourcepos=\"372:1-372:117\"\u003e競合を見つけたとき、つい「うまく順番調整して両方動かせないか」と考えがちです。\u003c/p\u003e\n\u003cp data-sourcepos=\"374:1-375:54\"\u003eもちろんそれで解決できることもありますが、\u003cbr\u003e\n保守を考えると、けっこう危ないです。\u003c/p\u003e\n\u003cp data-sourcepos=\"377:1-377:21\"\u003eなぜなら、後で\u003c/p\u003e\n\u003cul data-sourcepos=\"379:1-383:0\"\u003e\n\u003cli data-sourcepos=\"379:1-379:29\"\u003eプラグイン設定変更\u003c/li\u003e\n\u003cli data-sourcepos=\"380:1-380:32\"\u003e別のカスタマイズ追加\u003c/li\u003e\n\u003cli data-sourcepos=\"381:1-381:21\"\u003ekintone画面差分\u003c/li\u003e\n\u003cli data-sourcepos=\"382:1-383:0\"\u003e他担当者の改修\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"384:1-384:39\"\u003eでまた崩れやすいからです。\u003c/p\u003e\n\u003cp data-sourcepos=\"386:1-386:30\"\u003eそのため、個人的には\u003c/p\u003e\n\u003cdiv data-sourcepos=\"388:1-390:3\" class=\"note warn\"\u003e\n\u003cspan class=\"fa fa-fw fa-exclamation-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"389:1-389:76\"\u003e\u003cstrong\u003e無理に共存させるより、責務を整理して片方に寄せる\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp data-sourcepos=\"392:1-392:63\"\u003eほうが結果的に安定しやすいと感じています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"395:1-395:78\"\u003e\n\u003cspan id=\"4-便利そうだからプラグイン追加を少し慎重にする\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-%E4%BE%BF%E5%88%A9%E3%81%9D%E3%81%86%E3%81%A0%E3%81%8B%E3%82%89%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E8%BF%BD%E5%8A%A0%E3%82%92%E5%B0%91%E3%81%97%E6%85%8E%E9%87%8D%E3%81%AB%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4. 「便利そうだからプラグイン追加」を少し慎重にする\u003c/h2\u003e\n\u003cp data-sourcepos=\"397:1-397:42\"\u003eこれは少し運用寄りの話です。\u003c/p\u003e\n\u003cp data-sourcepos=\"399:1-400:62\"\u003ekintoneは便利なプラグインが多いので、つい足したくなります。\u003cbr\u003e\nただ、あとから自作JSを積んでいく前提なら、\u003c/p\u003e\n\u003cul data-sourcepos=\"402:1-406:0\"\u003e\n\u003cli data-sourcepos=\"402:1-402:44\"\u003eこのプラグインは何を触るのか\u003c/li\u003e\n\u003cli data-sourcepos=\"403:1-403:29\"\u003e画面制御に入るのか\u003c/li\u003e\n\u003cli data-sourcepos=\"404:1-404:26\"\u003e値更新に入るのか\u003c/li\u003e\n\u003cli data-sourcepos=\"405:1-406:0\"\u003e今後の拡張とぶつからないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"407:1-407:39\"\u003eは意識したほうがよいです。\u003c/p\u003e\n\u003cp data-sourcepos=\"409:1-409:136\"\u003e特に、\u003cstrong\u003e見た目も値もイベントも触る系のプラグイン\u003c/strong\u003eは便利な反面、競合しやすい印象があります。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"412:1-412:39\"\u003e\n\u003cspan id=\"困ったときの進め方まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%9B%B0%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE%E9%80%B2%E3%82%81%E6%96%B9%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e困ったときの進め方まとめ\u003c/h2\u003e\n\u003cp data-sourcepos=\"414:1-414:75\"\u003e最後に、私ならこう進める、という流れをまとめます。\u003c/p\u003e\n\u003cdiv data-sourcepos=\"416:1-427:3\" class=\"note info\"\u003e\n\u003cspan class=\"fa fa-fw fa-check-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"417:1-417:27\"\u003e困ったときの進め方\u003c/p\u003e\n\u003col data-sourcepos=\"419:1-426:0\"\u003e\n\u003cli data-sourcepos=\"419:1-419:41\"\u003eまずプラグイン競合を疑う\u003c/li\u003e\n\u003cli data-sourcepos=\"420:1-420:44\"\u003eアプリ複製で再現環境を作る\u003c/li\u003e\n\u003cli data-sourcepos=\"421:1-421:44\"\u003eどの画面で起きるか固定する\u003c/li\u003e\n\u003cli data-sourcepos=\"422:1-422:50\"\u003e触っているフィールドを洗い出す\u003c/li\u003e\n\u003cli data-sourcepos=\"423:1-423:67\"\u003e自作JS単体 / プラグイン単体 / 両方で比較する\u003c/li\u003e\n\u003cli data-sourcepos=\"424:1-424:99\"\u003econsoleログで「動いていない」のか「後で壊される」のかを切り分ける\u003c/li\u003e\n\u003cli data-sourcepos=\"425:1-426:0\"\u003e最終的には責務を分けて設計し直す\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 data-sourcepos=\"430:1-430:12\"\u003e\n\u003cspan id=\"まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまとめ\u003c/h2\u003e\n\u003cp data-sourcepos=\"432:1-432:134\"\u003ekintoneでJavaScriptを書いたときにハマる原因は、必ずしも「自分のコードミス」だけではありません。\u003c/p\u003e\n\u003cp data-sourcepos=\"434:1-434:66\"\u003e特に、既存プラグインが入っているアプリでは、\u003c/p\u003e\n\u003cul data-sourcepos=\"436:1-440:0\"\u003e\n\u003cli data-sourcepos=\"436:1-436:32\"\u003e同じフィールドを触る\u003c/li\u003e\n\u003cli data-sourcepos=\"437:1-437:44\"\u003e同じ画面タイミングで処理する\u003c/li\u003e\n\u003cli data-sourcepos=\"438:1-438:23\"\u003eDOMを直接いじる\u003c/li\u003e\n\u003cli data-sourcepos=\"439:1-440:0\"\u003eUI制御と値制御が重なる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"441:1-441:96\"\u003eといった条件が重なることで、かなり分かりづらい不具合になります。\u003c/p\u003e\n\u003cp data-sourcepos=\"443:1-443:69\"\u003eただ、見方を整理すると、対処しやすくなります。\u003c/p\u003e\n\u003cul data-sourcepos=\"445:1-449:0\"\u003e\n\u003cli data-sourcepos=\"445:1-445:23\"\u003eまず競合を疑う\u003c/li\u003e\n\u003cli data-sourcepos=\"446:1-446:17\"\u003e切り分ける\u003c/li\u003e\n\u003cli data-sourcepos=\"447:1-447:20\"\u003e役割を分ける\u003c/li\u003e\n\u003cli data-sourcepos=\"448:1-449:0\"\u003e無理な共存を減らす\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"450:1-450:75\"\u003eこのあたりを意識するだけでも、だいぶ楽になります。\u003c/p\u003e\n\u003cp data-sourcepos=\"452:1-452:174\"\u003e同じように「kintoneでJSを書いたら、なんかプラグインとぶつかってしんどい……」となっている方の参考になればうれしいです。\u003c/p\u003e\n","body":"## はじめに\nこんにちは。  \n業務改善エンジニアのこめまるです。\n\n今回は、kintoneでJavaScriptカスタマイズを書いたときに、**既存のプラグインが思った以上に邪魔をしてきた**話をまとめます。\n\nkintoneは手軽にカスタマイズできるのが魅力ですが、実際に触ってみると、\n\n- 自分で書いたJSが効かない\n- さっきまで動いていた処理が急におかしくなる\n- console上ではエラーが見えにくい\n- 原因が自作JSなのかプラグインなのか切り分けしづらい\n\nということがけっこう起こります。\n\n特に、**すでに何らかのプラグインが入っているアプリに後からJSを足す**場合は、想像以上にハマりやすいです。\n\n:::note info\nこの記事はこんな人におすすめ\n\n- kintoneでJavaScriptカスタマイズを書いている方\n- 「JSを書いたのに動かない」「なんか変な挙動になる」で困ったことがある方\n- プラグインとカスタマイズの競合を疑っている方\n- 困ったときの切り分け方や解決の進め方を知りたい方\n\n:::\n\nこの記事では、**実際に困りがちなポイント**と、**どうやって原因を切り分けて、どう解決していくか**を整理して書いていきます。\n\n\n## 先に結論\n\n最初に結論を書くと、kintoneでJSがうまく動かないときは、**自分のコード単体で考えないほうがよい**です。\n\n特に以下のような状況なら、プラグイン競合をかなり疑ったほうがよいです。\n\n- 同じフィールドを触っている\n- 同じ画面表示タイミングで処理している\n- DOMを直接触る系のJSを書いている\n- 入力制御系・表示制御系・一覧拡張系のプラグインが入っている\n\nつまり、\n\n:::note warn\n**「自作JSがバグっている」のではなく、  \n「プラグインと自作JSが同じ場所を触ってぶつかっている」**\n:::\n\nというケースが普通にあります。\n\nなので、困ったときはまず\n\n- プラグインを疑う\n- 影響範囲を切り分ける\n- DOM依存を減らす\n- イベントやフィールド操作の責任を整理する\n\nこの順で見ていくと、かなり進めやすいです。\n\n\n## どういうときに起こりやすいか\n\nkintoneで競合っぽい問題が起きやすいのは、だいたい以下のようなケースです。\n\n### 1. 同じフィールドを複数の仕組みが触っている\n\nたとえば、\n\n- プラグインがフィールドの表示・非表示を制御している\n- 自作JSでも同じフィールドを表示・非表示している\n- プラグインが値を自動設定している\n- 自作JSでも同じ値を書き換えている\n\nといったケースです。\n\nこの状態になると、**どちらが最後に効くのか**という話になりやすく、見た目としては\n\n- 一瞬表示されてすぐ消える\n- 値が入ったと思ったら戻る\n- 編集できるはずが編集できない\n\nのような、かなり分かりづらい症状になります。\n\n\n### 2. DOMを直接触っている\n\nこれはかなりハマりやすいです。\n\nkintoneカスタマイズでは、つい\n\n- 特定のclassを探して何かする\n- ボタンの位置を変える\n- 画面上の要素を直接隠す\n- ラベルや並び順を見た目ベースでいじる\n\nみたいなことをやりたくなります。\n\nただ、プラグイン側も同じようにDOMを触っていると、かなりぶつかりやすいです。\n\nしかも、DOMを直接触る系は\n\n- 画面構造の変化に弱い\n- プラグインの描画後処理に弱い\n- PC画面とモバイル画面で差が出やすい\n\nという問題もあるので、競合の温床になりやすいです。\n\n\n### 3. 一覧画面・詳細画面・編集画面で前提がズレる\n\n同じアプリでも、\n\n- 一覧\n- 詳細\n- 新規作成\n- 編集\n\nで画面の状態はかなり違います。\n\nここにプラグインも絡んでくると、たとえば\n\n- 一覧では動くのに詳細では動かない\n- 新規作成だけ変になる\n- 編集画面だけ項目が消える\n\nみたいなことが起きます。\n\nこのとき「たまたまその画面でバグる」のではなく、  \n**その画面だけプラグインの影響が強く出ている**こともあります。\n\n\n## 実際に困ったこと\n\nここからは、実際に起きがちな「困ったこと」をパターンで書きます。\n\n## 1. JSで値を入れても、あとから別の値に戻る\n\nこれはかなり典型です。\n\nたとえば、自作JSであるフィールドに値をセットしたのに、画面を見ると別の値になっているケースです。\n\n最初は「自分の代入処理が間違っているのかな」と思いがちですが、実際には\n\n- プラグイン側でも同じフィールドを更新している\n- 別イベントで後から上書きされている\n- フィールドの自動計算や変換処理が入っている\n\nということがあります。\n\n### このときの見方\n\n- どのフィールドが書き換わっているかを確認する\n- そのフィールドを触るプラグインがないか見る\n- イベント発火のたびに `console.log()` で値を追う\n\n### 解決法\n\n- 同じフィールドを複数箇所で更新しない\n- 値設定の責任を「JS側」か「プラグイン側」どちらかに寄せる\n- どうしても共存させるなら、対象フィールドを分ける\n\n:::note info\n**1つのフィールドに複数のロジックを集めすぎない**  \nこれだけでも、かなり事故が減ります。\n:::\n\n\n## 2. 表示・非表示の制御が思った通りにならない\n\nこれも多いです。\n\nたとえば、\n\n- JSでは表示したはずなのに見えない\n- 一瞬表示されるけど、あとで消える\n- 条件によって出し分けたいのに固定される\n\nというケースです。\n\nこのときは、表示制御系のプラグインが同じフィールドを触っていることが多いです。\n\n### 解決法\n\n- まず、そのフィールドの表示制御をプラグインが持っていないか確認する\n- 表示制御はなるべく1箇所に寄せる\n- JSとプラグインで分担するなら、対象フィールドを分ける\n- DOMの `display:none` ではなく、可能な範囲でkintone側の正式な操作に寄せる\n\nここで大事なのは、\n\n:::note warn\n**見た目を隠す処理** と **kintoneとしての表示制御** は同じではない\n:::\n\nということです。\n\n画面上で消えたように見えても、裏で状態がズレていると、後で別の不具合につながりやすいです。\n\n\n## 3. ボタンや追加UIが出たり出なかったりする\n\n自作JSでボタンやメッセージ領域を追加したときに、\n\n- 出る画面と出ない画面がある\n- リロードすると二重に出る\n- 位置が崩れる\n- プラグインのUIと重なる\n\nということがあります。\n\nこれは、DOM追加のタイミングや、再描画のされ方が影響していることが多いです。\n\n### 解決法\n\n- 同じ要素を何度も追加しないようにする\n- 追加前に既存要素の存在確認をする\n- 画面ごとのイベントを分けて考える\n- DOMの特定classに強く依存しすぎない\n\nたとえば、ボタン追加処理は「毎回追加」ではなく、  \n**なければ作る** くらいの作りにしておくと安定しやすいです。\n\n\n## 4. プラグインを入れたら急に自作JSが効かなくなった\n\nこれは一番わかりやすい症状です。\n\n「昨日までは動いていたのに、プラグインを入れたらダメになった」なら、かなり高確率で影響があります。\n\nただ、ここでありがちなのが、  \n**プラグインが悪いのではなく、両方が同じ前提に立っている**ケースです。\n\nつまり、\n\n- どちらも同じ場所にUIを出そうとしている\n- どちらも同じフィールドを必須/非必須っぽく扱っている\n- どちらも同じイベントで動こうとしている\n\nということです。\n\n### 解決法\n\nこの場合は、まず感情を捨てて切り分けます。\n\n#### 手順\n\n1. プラグインを一時的に外して再確認する  \n2. 自作JSを外してプラグイン単体でも確認する  \n3. どちらを入れたときに崩れるかを見る  \n4. 影響が出る画面を特定する  \n5. 触っているフィールドとイベントを洗い出す\n\nこれをやるだけで、だいぶ前に進みます。\n\n:::note info\n「とりあえずコードを直す」の前に、  \n**何と何がぶつかっているかを見つける** のが先です。\n:::\n\n\n## 切り分けのやり方\n\nここはかなり重要なので、手順でまとめます。\n\n## 1. まずはアプリを複製して検証する\n\n本番アプリや利用中アプリでそのまま試すと、余計に見えづらくなります。\n\nそのため、まずは複製したアプリで\n\n- プラグインあり\n- プラグインなし\n- 自作JSあり\n- 自作JSなし\n\nを試せる状態を作るのがおすすめです。\n\nこれだけで、かなり冷静に見られます。\n\n\n## 2. 何の画面で起きるかを固定する\n\n「なんか変」と言っても、画面が違えば原因も違います。\n\nなので、まずは以下を固定します。\n\n- 一覧画面か\n- 詳細画面か\n- 新規作成画面か\n- 編集画面か\n\nこの整理をしないまま見ると、話が散りやすいです。\n\n\n## 3. 触っているフィールドを洗い出す\n\n次に、\n\n- 自作JSが触っているフィールド\n- プラグインが触っていそうなフィールド\n\nを一覧にします。\n\nこれをやると、かなり見えてきます。\n\n特に、以下が重なっていたら要注意です。\n\n- 表示制御対象\n- 値の自動設定対象\n- 必須っぽい扱いをしている項目\n- 参照/計算に使っている項目\n\n\n## 4. consoleでログを出す\n\nシンプルですが強いです。\n\nたとえば、\n\n- イベントが本当に発火しているか\n- その時点の値が何か\n- どの分岐に入ったか\n\nをログで出すだけでも、かなり状況が見えます。\n\n```javascript\nconsole.log('編集画面表示イベント');\nconsole.log('対象フィールドの値:', record.sample_field.value);\n```\n\nこういうログを、要所だけでも入れておくと、  \n「そもそも自分のJSが動いていないのか」「動いたあとで壊されているのか」が分かりやすくなります。\n\n\n## 解決の考え方\n\nここからは、私が実際に「こう考えると直しやすい」と感じたポイントです。\n\n## 1. 役割を分ける\n\n一番大事なのはこれです。\n\n- 表示制御はどっちが担当するか\n- 値設定はどっちが担当するか\n- UI追加はどっちが担当するか\n\nを曖昧にしないことです。\n\nプラグインと自作JSが共存するときは、  \n**同じ責務を両方に持たせない**のが基本です。\n\n\n## 2. DOM操作を減らす\n\nkintoneでは、見た目を直接いじるより、  \nまずは「正式に触れる範囲」で解決できないか考えたほうが安定します。\n\nDOM直操作が必要な場面もありますが、  \nそれをやるほどプラグインとの競合確率は上がる印象です。\n\nなので、\n\n- まずはレコード値ベースで解決できないか\n- フィールド制御で済まないか\n- UI追加だけで済まないか\n\nを先に考えるのがおすすめです。\n\n\n## 3. スマートに直そうとしすぎない\n\n競合を見つけたとき、つい「うまく順番調整して両方動かせないか」と考えがちです。\n\nもちろんそれで解決できることもありますが、  \n保守を考えると、けっこう危ないです。\n\nなぜなら、後で\n\n- プラグイン設定変更\n- 別のカスタマイズ追加\n- kintone画面差分\n- 他担当者の改修\n\nでまた崩れやすいからです。\n\nそのため、個人的には\n\n:::note warn\n**無理に共存させるより、責務を整理して片方に寄せる**\n:::\n\nほうが結果的に安定しやすいと感じています。\n\n\n## 4. 「便利そうだからプラグイン追加」を少し慎重にする\n\nこれは少し運用寄りの話です。\n\nkintoneは便利なプラグインが多いので、つい足したくなります。  \nただ、あとから自作JSを積んでいく前提なら、\n\n- このプラグインは何を触るのか\n- 画面制御に入るのか\n- 値更新に入るのか\n- 今後の拡張とぶつからないか\n\nは意識したほうがよいです。\n\n特に、**見た目も値もイベントも触る系のプラグイン**は便利な反面、競合しやすい印象があります。\n\n\n## 困ったときの進め方まとめ\n\n最後に、私ならこう進める、という流れをまとめます。\n\n:::note info\n困ったときの進め方\n\n1. まずプラグイン競合を疑う  \n2. アプリ複製で再現環境を作る  \n3. どの画面で起きるか固定する  \n4. 触っているフィールドを洗い出す  \n5. 自作JS単体 / プラグイン単体 / 両方で比較する  \n6. consoleログで「動いていない」のか「後で壊される」のかを切り分ける  \n7. 最終的には責務を分けて設計し直す\n\n:::\n\n\n## まとめ\n\nkintoneでJavaScriptを書いたときにハマる原因は、必ずしも「自分のコードミス」だけではありません。\n\n特に、既存プラグインが入っているアプリでは、\n\n- 同じフィールドを触る\n- 同じ画面タイミングで処理する\n- DOMを直接いじる\n- UI制御と値制御が重なる\n\nといった条件が重なることで、かなり分かりづらい不具合になります。\n\nただ、見方を整理すると、対処しやすくなります。\n\n- まず競合を疑う\n- 切り分ける\n- 役割を分ける\n- 無理な共存を減らす\n\nこのあたりを意識するだけでも、だいぶ楽になります。\n\n同じように「kintoneでJSを書いたら、なんかプラグインとぶつかってしんどい……」となっている方の参考になればうれしいです。\n","coediting":false,"comments_count":0,"created_at":"2026-04-09T08:16:45+09:00","group":null,"id":"bd3a9c50df4d008b2d4e","likes_count":6,"private":false,"reactions_count":0,"stocks_count":2,"tags":[{"name":"JavaScript","versions":[]},{"name":"プラグイン","versions":[]},{"name":"kintone","versions":[]},{"name":"カスタマイズ","versions":[]},{"name":"業務改善","versions":[]}],"title":" kintoneでJavaScriptを書いたらプラグインが邪魔した話｜困ったことと解決法をまとめる","updated_at":"2026-04-09T08:16:45+09:00","url":"https://qiita.com/komemaru/items/bd3a9c50df4d008b2d4e","user":{"description":"業務改善エンジニア／情報処理安全確保支援士。RPA、kintone、Power Platform、生成AIを活用した業務効率化に取り組んでいます。実務で得た知見や技術メモを発信しています。\r\n","facebook_id":"","followees_count":1,"followers_count":2,"github_login_name":null,"id":"komemaru","items_count":8,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":4401379,"profile_image_url":"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4401379/profile-images/1775526468","team_only":false,"twitter_screen_name":"komemaru_dx","website_url":""},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:123\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F1317e65b-5744-4d96-91bc-5994117af803.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=35ec3a2f57db1d983183b97681362a17\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F1317e65b-5744-4d96-91bc-5994117af803.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=35ec3a2f57db1d983183b97681362a17\" alt=\"day008.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F1317e65b-5744-4d96-91bc-5994117af803.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=38b24c2889246135defb8dfdbd36df0c 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/1317e65b-5744-4d96-91bc-5994117af803.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"4:1-6:140\"\u003e面倒解決エンジニアの森田ユウゴです。\u003cbr\u003e\n台湾からお届けする「#kintone100日チャレンジ」の記念すべき 8 日目。\u003cbr\u003e\n昨日までの2回は実用性に欠ける開発だったので、現実的に使えそうなkintoneの悩みを解決してみました。\u003c/p\u003e\n\u003cp data-sourcepos=\"8:1-8:107\"\u003e👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジの概要はこちら\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"10:1-10:189\"\u003e本日は、kintoneとRDBで最も違う点と言える「テーブル」をより便利に閲覧するための「\u003cstrong\u003eSubtable Plus（テーブル・プラス）\u003c/strong\u003e」を開発しました！\u003c/p\u003e\n\u003ch2 data-sourcepos=\"12:1-12:64\"\u003e\n\u003cspan id=\"subtable-plusテーブルプラスについて\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#subtable-plus%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%83%97%E3%83%A9%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e「Subtable Plus（テーブル・プラス）」について\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"13:1-13:75\"\u003e\n\u003cspan id=\"-なぜ開発したか現場の課題とベネフィット\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%AA%E3%81%9C%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E3%81%8B%E7%8F%BE%E5%A0%B4%E3%81%AE%E8%AA%B2%E9%A1%8C%E3%81%A8%E3%83%99%E3%83%8D%E3%83%95%E3%82%A3%E3%83%83%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🎯 なぜ開発したか？（現場の課題とベネフィット）\u003c/h3\u003e\n\u003cul data-sourcepos=\"14:1-17:0\"\u003e\n\u003cli data-sourcepos=\"14:1-15:185\"\u003e\n\u003cstrong\u003e現場の「不」:\u003c/strong\u003e kintoneのテーブルは、行数や列数が増えると画面を大きく圧迫し、スクロール地獄に陥りがちです。特定の列だけ見たい、特定の行だけ非表示にしたい、テキストエリアの長文が邪魔、サクッとCSVで取り出したい…といった「閲覧時」の細かな不便が積み重なり、テーブルを避けることも多いです。\u003cbr\u003e\n一方、ルックアップなどせずに手軽にデータ入力をしたい！という場面では必須のため、基本機能では悩みながら使うことも多いです。\u003c/li\u003e\n\u003cli data-sourcepos=\"16:1-17:0\"\u003e\n\u003cstrong\u003e導入後の世界（ベネフィット）:\u003c/strong\u003e 特定行数列など画面がスッキリ！検索機能で目的の行に一瞬でアクセスでき、見たい列だけを絞り込んで確認できます。ワンクリックでのCSVコピー機能により、別ツールへのデータ転記の手間とミスを撲滅します。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"18:1-18:50\"\u003e\n\u003cspan id=\"-これで出来ること機能概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%93%E3%82%8C%E3%81%A7%E5%87%BA%E6%9D%A5%E3%82%8B%E3%81%93%E3%81%A8%E6%A9%9F%E8%83%BD%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e✨ これで出来ること（機能概要）\u003c/h3\u003e\n\u003cp data-sourcepos=\"19:1-19:42\"\u003eまずはこちらをご覧ください。\u003c/p\u003e\n\u003ciframe width=\"100%\" height=\"315\" src=\"https://www.youtube.com/embed/MXZVWZG6NHw\" frameborder=\"0\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cul data-sourcepos=\"23:1-26:0\"\u003e\n\u003cli data-sourcepos=\"23:1-23:236\"\u003e\n\u003cstrong\u003eスッキリ見やすい表示制御:\u003c/strong\u003e アコーディオン（もっと見る）やページング機能で長すぎるテーブルをスッキリ収納。セル内の長文も「続きを読む」で折りたたみ可能です。\u003c/li\u003e\n\u003cli data-sourcepos=\"24:1-24:302\"\u003e\n\u003cstrong\u003e高度なデータ探索・操作:\u003c/strong\u003e Cybozu CDNが用意してくれているライブラリ「DataTables」を用いたソート、検索＆キーワードハイライト機能。さらに、列ごとの表示/非表示切り替えや、不要な行の一時非表示にも対応しています。\u003c/li\u003e\n\u003cli data-sourcepos=\"25:1-26:0\"\u003e\n\u003cstrong\u003e実務に寄り添う便利機能:\u003c/strong\u003e 行番号の自動付与、ワンクリックでクリップボードへ送れる「CSVコピー機能」、そして印刷時には隠れた行を自動で全展開する機能など、かゆいところに手が届く仕様です。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"27:1-27:10\"\u003e\n\u003cspan id=\"課題\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%AA%B2%E9%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e課題\u003c/h3\u003e\n\u003cp data-sourcepos=\"28:1-28:63\"\u003e現時点では下記のような課題が残っています。\u003c/p\u003e\n\u003cul data-sourcepos=\"29:1-36:0\"\u003e\n\u003cli data-sourcepos=\"29:1-30:522\"\u003e\n\u003cstrong\u003eUI/UXと設定画面の最適化\u003c/strong\u003e\u003cbr\u003e\n  「出来ることを確認する」ことが第一の目的だったため、一つ一つの機能を精査しきれておらず、最適な見た目とは言えない部分があります。また、設定画面も項目を羅列しただけで直感的に設定しづらいため、上部にプレビューなどを配置する余地があります。テーブルを見る中での「不便」はある程度洗い出せたので、もう少しブラッシュアップすれば劇的に便利になりそうです。\u003c/li\u003e\n\u003cli data-sourcepos=\"31:1-32:186\"\u003e\n\u003cstrong\u003e入力画面への非対応\u003c/strong\u003e\u003cbr\u003e\n  あくまで「レコード詳細画面（閲覧時）」のみを対象としているため、編集画面での入力のしやすさ向上にはまだ貢献できていません。\u003c/li\u003e\n\u003cli data-sourcepos=\"33:1-36:0\"\u003e\n\u003cstrong\u003eあくまでDOM操作\u003c/strong\u003e\u003cbr\u003e\n  AIに対してはgetFieldElement(id)で取得した値をもとに雑に実装をしてもらったのですが、かなり飲み込みが早かったです。\u003cbr\u003e\nしかし、DOM操作なのでkintoneのアップデートには追従が必要です。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"37:1-37:15\"\u003e\n\u003cspan id=\"さいごに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eさいごに\u003c/h2\u003e\n\u003cp data-sourcepos=\"39:1-39:27\"\u003e明日もお楽しみに！\u003c/p\u003e\n\u003cp data-sourcepos=\"41:1-43:180\"\u003e下記のブログもご覧ください！\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！\u003c/a\u003e\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/kintone-support-service-coconala/\" rel=\"nofollow noopener\" target=\"_blank\"\u003eココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"45:1-45:114\"\u003e2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\u003c/p\u003e\n\u003cblockquote class=\"twitter-tweet\"\u003e\n\u003cp\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e— 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003eApril 15, 2026\u003c/a\u003e\n\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\"\u003e\u003c/script\u003e\n","body":"![day008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/1317e65b-5744-4d96-91bc-5994117af803.png)\n\n\n面倒解決エンジニアの森田ユウゴです。\n台湾からお届けする「#kintone100日チャレンジ」の記念すべき 8 日目。\n昨日までの2回は実用性に欠ける開発だったので、現実的に使えそうなkintoneの悩みを解決してみました。\n\n👉 [#kintone100日チャレンジの概要はこちら](https://moritayugo.com/100days-of-kintone-hacks/)\n\n本日は、kintoneとRDBで最も違う点と言える「テーブル」をより便利に閲覧するための「**Subtable Plus（テーブル・プラス）**」を開発しました！\n\n## 「Subtable Plus（テーブル・プラス）」について\n### 🎯 なぜ開発したか？（現場の課題とベネフィット）\n- **現場の「不」:** kintoneのテーブルは、行数や列数が増えると画面を大きく圧迫し、スクロール地獄に陥りがちです。特定の列だけ見たい、特定の行だけ非表示にしたい、テキストエリアの長文が邪魔、サクッとCSVで取り出したい…といった「閲覧時」の細かな不便が積み重なり、テーブルを避けることも多いです。\n  一方、ルックアップなどせずに手軽にデータ入力をしたい！という場面では必須のため、基本機能では悩みながら使うことも多いです。\n- **導入後の世界（ベネフィット）:** 特定行数列など画面がスッキリ！検索機能で目的の行に一瞬でアクセスでき、見たい列だけを絞り込んで確認できます。ワンクリックでのCSVコピー機能により、別ツールへのデータ転記の手間とミスを撲滅します。\n\n### ✨ これで出来ること（機能概要）\nまずはこちらをご覧ください。\n\n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/MXZVWZG6NHw\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\n- **スッキリ見やすい表示制御:** アコーディオン（もっと見る）やページング機能で長すぎるテーブルをスッキリ収納。セル内の長文も「続きを読む」で折りたたみ可能です。\n- **高度なデータ探索・操作:** Cybozu CDNが用意してくれているライブラリ「DataTables」を用いたソート、検索＆キーワードハイライト機能。さらに、列ごとの表示/非表示切り替えや、不要な行の一時非表示にも対応しています。\n- **実務に寄り添う便利機能:** 行番号の自動付与、ワンクリックでクリップボードへ送れる「CSVコピー機能」、そして印刷時には隠れた行を自動で全展開する機能など、かゆいところに手が届く仕様です。\n\n### 課題\n現時点では下記のような課題が残っています。\n- **UI/UXと設定画面の最適化**\n  「出来ることを確認する」ことが第一の目的だったため、一つ一つの機能を精査しきれておらず、最適な見た目とは言えない部分があります。また、設定画面も項目を羅列しただけで直感的に設定しづらいため、上部にプレビューなどを配置する余地があります。テーブルを見る中での「不便」はある程度洗い出せたので、もう少しブラッシュアップすれば劇的に便利になりそうです。\n- **入力画面への非対応**\n  あくまで「レコード詳細画面（閲覧時）」のみを対象としているため、編集画面での入力のしやすさ向上にはまだ貢献できていません。\n- **あくまでDOM操作**\n  AIに対してはgetFieldElement(id)で取得した値をもとに雑に実装をしてもらったのですが、かなり飲み込みが早かったです。\n  しかし、DOM操作なのでkintoneのアップデートには追従が必要です。\n\n## さいごに\n\n明日もお楽しみに！\n\n下記のブログもご覧ください！\n👉 [【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！](https://moritayugo.com/100days-of-kintone-hacks/)\n👉 [ココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！](https://moritayugo.com/kintone-support-service-coconala/)\n\n2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\n\u003cblockquote class=\"twitter-tweet\"\u003e\u003cp lang=\"ja\" dir=\"ltr\"\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e\u0026mdash; 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\"\u003eApril 15, 2026\u003c/a\u003e\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\n","coediting":false,"comments_count":0,"created_at":"2026-04-08T17:51:57+09:00","group":null,"id":"a939251d0429b523e688","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"kintoneplugin","versions":[]},{"name":"バイブコーディング","versions":[]},{"name":"kintoneカスタマイズ","versions":[]},{"name":"kintone100日チャレンジ","versions":[]}],"title":"【#kintone100日チャレンジ】Day 8: 詳細画面のテーブルを見やすくする「テーブル・プラス」を作ってみた","updated_at":"2026-04-15T09:55:53+09:00","url":"https://qiita.com/majinalife/items/a939251d0429b523e688","user":{"description":"台湾在住の「面倒解決エンジニア」です。\r\n#kintone #Anki Chrome拡張など得意分野です💻\r\nアプリデザインスペシャリスト(2025)\r\nカスタマイズスペシャリスト(2026) \r\nお仕事のご依頼を承っておりますのでお気軽にご相談ください！","facebook_id":"","followees_count":1,"followers_count":1,"github_login_name":null,"id":"majinalife","items_count":13,"linkedin_id":"","location":"台湾","name":"森田 ユウゴ","organization":"","permanent_id":3990248,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3990248/795e2d2e68ab72ba29dc3224f01546c658346fc2/large.png?1774234714","team_only":false,"twitter_screen_name":"majinalife_blog","website_url":"https://moritayugo.com/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:146\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/c88067818cf41424615f\" id=\"reference-9df952484624ccee1153\"\u003ekintone でSQL実行しよう その９（パフォーマンス改善）\u003c/a\u003eの続きです。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"3:1-3:8\"\u003e\n\u003cspan id=\"概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e概要\u003c/h1\u003e\n\u003cp data-sourcepos=\"5:1-6:207\"\u003ekintone アプリ上でSQL操作するだけではなく、cli（コマンドラインインターフェイス）対応してみました。\u003cbr\u003e\n操作対象の kintone 環境をプロファイルとして複数指定することで、ゲストスペースアプリとの結合や、複数の kintone 環境のアプリも一緒に結合できます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"8:1-8:9\"\u003e\n\u003cspan id=\"名前\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%90%8D%E5%89%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e名前\u003c/h2\u003e\n\u003cp data-sourcepos=\"10:1-11:110\"\u003ecli-ksql です。\u003cbr\u003e\ncli-ksql は、kintoneデータを SQLライクな書き方で扱えるコマンドラインツールです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"13:1-13:21\"\u003e\n\u003cspan id=\"cli-ksql-の特長\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#cli-ksql-%E3%81%AE%E7%89%B9%E9%95%B7\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ecli-ksql の特長\u003c/h2\u003e\n\u003cul data-sourcepos=\"15:1-20:0\"\u003e\n\u003cli data-sourcepos=\"15:1-15:50\"\u003eSQL風なので、条件指定が読みやすい\u003c/li\u003e\n\u003cli data-sourcepos=\"16:1-16:46\"\u003eJOINや集計を1つのクエリで書ける\u003c/li\u003e\n\u003cli data-sourcepos=\"17:1-17:54\"\u003eREPL（対話モード）で試行錯誤しやすい\u003c/li\u003e\n\u003cli data-sourcepos=\"18:1-18:42\"\u003e\n\u003ccode\u003eEXPLAIN\u003c/code\u003e で実行前に確認できる\u003c/li\u003e\n\u003cli data-sourcepos=\"19:1-20:0\"\u003e\n\u003ccode\u003eAPP@profile\u003c/code\u003e で環境を切り替えられる\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"21:1-21:15\"\u003e\n\u003cspan id=\"実行環境\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実行環境\u003c/h2\u003e\n\u003cul data-sourcepos=\"23:1-28:0\"\u003e\n\u003cli data-sourcepos=\"23:1-23:56\"\u003e\n\u003ccode\u003eNode.js\u003c/code\u003e が動く環境（Windows / macOS / Linux）\u003c/li\u003e\n\u003cli data-sourcepos=\"24:1-24:23\"\u003e\n\u003ccode\u003enpm\u003c/code\u003e が利用可能\u003c/li\u003e\n\u003cli data-sourcepos=\"25:1-25:52\"\u003ekintone にアクセスできるネットワーク\u003c/li\u003e\n\u003cli data-sourcepos=\"26:1-26:68\"\u003ekintone 認証情報（\u003ccode\u003euser/pass\u003c/code\u003e もしくは APIトークン）\u003c/li\u003e\n\u003cli data-sourcepos=\"27:1-28:0\"\u003e文字コード UTF-8 のターミナル（PowerShell / bash など）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"29:1-29:34\"\u003e実行例（Windows PowerShell）:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"powershell\" data-sourcepos=\"30:1-32:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003enode\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003e\\dist-cli\\ksql.js\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nt\"\u003e-e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\"SELECT 'ABC' as a;\"\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"34:1-34:32\"\u003e\n\u003cspan id=\"cli-ksql-でできること\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#cli-ksql-%E3%81%A7%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003ecli-ksql\u003c/code\u003e でできること\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"36:1-36:35\"\u003e\n\u003cspan id=\"1-まずは1行で動作確認\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E3%81%BE%E3%81%9A%E3%81%AF1%E8%A1%8C%E3%81%A7%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. まずは1行で動作確認\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"37:1-39:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"s1\"\u003e'ABC'\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"41:1-41:32\"\u003e\n\u003cspan id=\"2-1つのアプリを検索\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-1%E3%81%A4%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E6%A4%9C%E7%B4%A2\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. 1つのアプリを検索\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"42:1-48:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e会社名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4148\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e \u003cspan class=\"k\"\u003eIN\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e'A'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e \u003cspan class=\"mi\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"50:1-50:30\"\u003e\n\u003cspan id=\"3-2つのアプリをjoin\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-2%E3%81%A4%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92join\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. 2つのアプリをJOIN\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"51:1-61:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e\n  \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e会社名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"err\"\u003e案件\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e案件名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n  \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e商談フェーズ\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4148\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\n\u003cspan class=\"k\"\u003eINNER\u003c/span\u003e \u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP4149\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\n  \u003cspan class=\"k\"\u003eON\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"k\"\u003eNo\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客\u003c/span\u003e\u003cspan class=\"n\"\u003eNo_\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"63:1-63:34\"\u003e\n\u003cspan id=\"4-結果をエクスポート\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-%E7%B5%90%E6%9E%9C%E3%82%92%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4. 結果をエクスポート\u003c/h3\u003e\n\u003cul data-sourcepos=\"64:1-66:0\"\u003e\n\u003cli data-sourcepos=\"64:1-64:6\"\u003eJSON\u003c/li\u003e\n\u003cli data-sourcepos=\"65:1-66:0\"\u003eCSV\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 data-sourcepos=\"67:1-67:41\"\u003e\n\u003cspan id=\"cli-ksql-のしくみ内部構成\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#cli-ksql-%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF%E5%86%85%E9%83%A8%E6%A7%8B%E6%88%90\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ecli-ksql のしくみ（内部構成）\u003c/h1\u003e\n\u003cp data-sourcepos=\"69:1-70:105\"\u003e\u003ccode\u003ecli-ksql\u003c/code\u003e は、SQL文字列を AST(Abstract Syntax Tree) に変換し、kintone API 実行計画へ落として実行する構成です。\u003cbr\u003e\n実装上は \u003ccode\u003esrc/cli\u003c/code\u003e（CLI層）と \u003ccode\u003esrc/execute.ts\u003c/code\u003e（実行エンジン）を中心に動きます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"72:1-72:15\"\u003e\n\u003cspan id=\"全体構成\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%85%A8%E4%BD%93%E6%A7%8B%E6%88%90\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e全体構成\u003c/h2\u003e\n\u003ciframe id=\"qiita-embed-content__5af5d7bf5ac2f70826e3718f8c76c1cb\" src=\"https://qiita.com/embed-contents/mermaid#qiita-embed-content__5af5d7bf5ac2f70826e3718f8c76c1cb\" style=\"width:100%;\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" data-content='{\"data\":\"flowchart LR\\n U[\\\"User (CLI / REPL)\\\"] --\u0026gt; C[\\\"src/cli/index.ts\\\\n引数解析・設定読込・ガード\\\"]\\n C --\u0026gt; P[\\\"normalizeSqlAppProfiles()\\\\nAPP@profile 正規化\\\"]\\n P --\u0026gt; E[\\\"execute(sql, client, options)\\\\nsrc/execute.ts\\\"]\\n\\n E --\u0026gt; L[\\\"Lexer\\\\nsrc/lexer/lexer.ts\\\"]\\n L --\u0026gt; R[\\\"Parser\\\\nsrc/parser/parser.ts\\\"]\\n R --\u0026gt; A[\\\"AST (Statement)\\\\nsrc/types/ast.ts\\\"]\\n\\n A --\u0026gt; M[\\\"Select mode 判定\\\\nresolveSelectMode()\\\"]\\n M --\u0026gt; S[\\\"SIMPLE path\\\\nselectToKintone / whereToKintone\\\"]\\n M --\u0026gt; F[\\\"FULL_SCAN path\\\\nfetchAll + runFullScan\\\"]\\n\\n S --\u0026gt; K[\\\"KintoneClient\\\\n(get/post/put/delete/getApps/getFields)\\\"]\\n F --\u0026gt; K\\n\\n K --\u0026gt; N[\\\"src/cli/nodeKintoneClient.ts\\\\n/k/v1 or /k/guest/\u0026lt;id\u0026gt;/v1 呼び出し\\\"]\\n N --\u0026gt; API[\\\"kintone REST API\\\"]\\n\\n E --\u0026gt; O[\\\"formatDisplayText()\\\\n表示整形\\\"]\\n O --\u0026gt; OUT[\\\"table / json / jsonl / csv / --output\\\"]\",\"key\":\"6a157665f5ef9c74fa3d444c560e23bb\"}'\u003e\n\u003c/iframe\u003e\n\n\u003ch2 data-sourcepos=\"98:1-98:25\"\u003e\n\u003cspan id=\"select-実行フロー\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#select-%E5%AE%9F%E8%A1%8C%E3%83%95%E3%83%AD%E3%83%BC\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eSELECT 実行フロー\u003c/h2\u003e\n\u003ciframe id=\"qiita-embed-content__eea03d31a3f8ad29cb83182692db9167\" src=\"https://qiita.com/embed-contents/mermaid#qiita-embed-content__eea03d31a3f8ad29cb83182692db9167\" style=\"width:100%;\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" data-content=\"{\u0026quot;data\u0026quot;:\u0026quot;flowchart TD\\n Q[\\\u0026quot;SQL 入力\\\u0026quot;] --\u0026gt; X[\\\u0026quot;parseSql()\\\u0026quot;]\\n X --\u0026gt; Y{\\\u0026quot;FROM 省略?\\\u0026quot;}\\n Y -- \\\u0026quot;yes\\\u0026quot; --\u0026gt; Z[\\\u0026quot;executeNoFromSelect()\\\\n例: SELECT 'ABC' as a;\\\u0026quot;]\\n Y -- \\\u0026quot;no\\\u0026quot; --\u0026gt; W[\\\u0026quot;resolveSelectMode()\\\u0026quot;]\\n\\n W --\u0026gt; T{\\\u0026quot;mode\\\u0026quot;}\\n T -- \\\u0026quot;SIMPLE\\\u0026quot; --\u0026gt; S1[\\\u0026quot;executeSimpleSelect()\\\\n可能なら kintone クエリへ変換\\\u0026quot;]\\n T -- \\\u0026quot;FULL_SCAN\\\u0026quot; --\u0026gt; F1[\\\u0026quot;executeFullScanSelect()\\\\n全件取得して JS 評価\\\u0026quot;]\\n\\n S1 --\u0026gt; G1[\\\u0026quot;client.getRecords() / fetchAll()\\\u0026quot;]\\n F1 --\u0026gt; G2[\\\u0026quot;fetchAll() -\u0026gt; runFullScan()\\\u0026quot;]\\n\\n G1 --\u0026gt; R1[\\\u0026quot;project/order/limit\\\u0026quot;]\\n G2 --\u0026gt; R1\\n Z --\u0026gt; R1\\n R1 --\u0026gt; RES[\\\u0026quot;SelectResult rows/columns\\\u0026quot;]\u0026quot;,\u0026quot;key\u0026quot;:\u0026quot;43ad10014da70a0646c09b6a08294505\u0026quot;}\"\u003e\n\u003c/iframe\u003e\n\n\u003ch2 data-sourcepos=\"120:1-120:33\"\u003e\n\u003cspan id=\"モジュールごとの役割\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%94%E3%81%A8%E3%81%AE%E5%BD%B9%E5%89%B2\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eモジュールごとの役割\u003c/h2\u003e\n\u003cul data-sourcepos=\"122:1-138:0\"\u003e\n\u003cli data-sourcepos=\"122:1-126:79\"\u003e\n\u003ccode\u003esrc/cli/index.ts\u003c/code\u003e\n\u003cul data-sourcepos=\"123:3-126:79\"\u003e\n\u003cli data-sourcepos=\"123:3-123:36\"\u003e\n\u003ccode\u003eparseArgs()\u003c/code\u003e で引数を解析\u003c/li\u003e\n\u003cli data-sourcepos=\"124:3-124:28\"\u003econfig/profile を解決\u003c/li\u003e\n\u003cli data-sourcepos=\"125:3-125:62\"\u003e\n\u003ccode\u003enormalizeSqlAppProfiles()\u003c/code\u003e で \u003ccode\u003eAPP@profile\u003c/code\u003e を正規化\u003c/li\u003e\n\u003cli data-sourcepos=\"126:3-126:79\"\u003eDML ガード（\u003ccode\u003e--allow-dml\u003c/code\u003e, \u003ccode\u003e--allow-without-where\u003c/code\u003e, \u003ccode\u003e--dml-max-rows\u003c/code\u003e）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"127:1-129:96\"\u003e\n\u003ccode\u003esrc/execute.ts\u003c/code\u003e\n\u003cul data-sourcepos=\"128:3-129:96\"\u003e\n\u003cli data-sourcepos=\"128:3-128:64\"\u003e\n\u003ccode\u003eexecute()\u003c/code\u003e が文種別ごとに処理をルーティング\u003c/li\u003e\n\u003cli data-sourcepos=\"129:3-129:96\"\u003e\n\u003ccode\u003eSELECT/UNION/WITH/INSERT/UPDATE/DELETE/UPSERT/REORDER/SHOW APPS/DESCRIBE/EXPLAIN\u003c/code\u003e を処理\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"130:1-131:52\"\u003e\n\u003ccode\u003esrc/converter/*\u003c/code\u003e\n\u003cul data-sourcepos=\"131:3-131:52\"\u003e\n\u003cli data-sourcepos=\"131:3-131:52\"\u003eSQL AST を kintone API パラメータへ変換\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"132:1-133:83\"\u003e\n\u003ccode\u003esrc/engine/*\u003c/code\u003e\n\u003cul data-sourcepos=\"133:3-133:83\"\u003e\n\u003cli data-sourcepos=\"133:3-133:83\"\u003eFULL_SCAN 時の式評価、WHERE 評価、JOIN/GROUP BY/HAVING/ORDER BY 処理\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"134:1-135:43\"\u003e\n\u003ccode\u003esrc/api/fetchAll.ts\u003c/code\u003e\n\u003cul data-sourcepos=\"135:3-135:43\"\u003e\n\u003cli data-sourcepos=\"135:3-135:43\"\u003eページングしながら全件取得\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"136:1-138:0\"\u003e\n\u003ccode\u003esrc/cli/nodeKintoneClient.ts\u003c/code\u003e\n\u003cul data-sourcepos=\"137:3-138:0\"\u003e\n\u003cli data-sourcepos=\"137:3-138:0\"\u003eNode.js から kintone REST API を呼び出す薄いクライアント\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"139:1-139:26\"\u003e\n\u003cspan id=\"appprofile-の流れ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#appprofile-%E3%81%AE%E6%B5%81%E3%82%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003eAPP@profile\u003c/code\u003e の流れ\u003c/h2\u003e\n\u003col data-sourcepos=\"141:1-145:0\"\u003e\n\u003cli data-sourcepos=\"141:1-141:53\"\u003eCLI で SQL 中の \u003ccode\u003eAPP4148@dev\u003c/code\u003e などを検出\u003c/li\u003e\n\u003cli data-sourcepos=\"142:1-142:70\"\u003e\n\u003ccode\u003e@profile\u003c/code\u003e を外した正規化SQLを実行エンジンへ渡す\u003c/li\u003e\n\u003cli data-sourcepos=\"143:1-143:99\"\u003e実行時の app-\u0026gt;profile 束縛を保持し、対応する接続先 client に振り分ける\u003c/li\u003e\n\u003cli data-sourcepos=\"144:1-145:0\"\u003e同一SQL内で同一APPに複数profileが混在しても、内部仮想 appId で衝突回避\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 data-sourcepos=\"146:1-146:12\"\u003e\n\u003cspan id=\"まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまとめ\u003c/h2\u003e\n\u003cul data-sourcepos=\"148:1-151:0\"\u003e\n\u003cli data-sourcepos=\"148:1-148:45\"\u003eCLI は「入力と実行環境の解決」\u003c/li\u003e\n\u003cli data-sourcepos=\"149:1-149:52\"\u003eexecute は「SQLの意味解釈と実行制御」\u003c/li\u003e\n\u003cli data-sourcepos=\"150:1-151:0\"\u003econverter/engine は「kintone API に寄せる層」と「JSで補完する層」\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"152:1-153:101\"\u003eという分担です。\u003cbr\u003e\nこの分離によって、プラグインUIとCLIが同じコアロジックを共有できます。\u003c/p\u003e\n","body":"[kintone でSQL実行しよう その９（パフォーマンス改善）](https://qiita.com/rex0220/items/c88067818cf41424615f)の続きです。\n\n# 概要\n\nkintone アプリ上でSQL操作するだけではなく、cli（コマンドラインインターフェイス）対応してみました。\n操作対象の kintone 環境をプロファイルとして複数指定することで、ゲストスペースアプリとの結合や、複数の kintone 環境のアプリも一緒に結合できます。\n\n## 名前\n\ncli-ksql です。\ncli-ksql は、kintoneデータを SQLライクな書き方で扱えるコマンドラインツールです。\n\n## cli-ksql の特長\n\n- SQL風なので、条件指定が読みやすい\n- JOINや集計を1つのクエリで書ける\n- REPL（対話モード）で試行錯誤しやすい\n- `EXPLAIN` で実行前に確認できる\n- `APP@profile` で環境を切り替えられる\n\n## 実行環境\n\n- `Node.js` が動く環境（Windows / macOS / Linux）\n- `npm` が利用可能\n- kintone にアクセスできるネットワーク\n- kintone 認証情報（`user/pass` もしくは APIトークン）\n- 文字コード UTF-8 のターミナル（PowerShell / bash など）\n\n実行例（Windows PowerShell）:\n```powershell\nnode .\\dist-cli\\ksql.js -e \"SELECT 'ABC' as a;\"\n```\n\n## `cli-ksql` でできること\n\n### 1. まずは1行で動作確認\n```sql\nSELECT 'ABC' as a;\n```\n\n### 2. 1つのアプリを検索\n```sql\nSELECT 顧客No, 会社名, 顧客ランク\nFROM APP4148\nWHERE 顧客ランク IN ('A')\nORDER BY 顧客No DESC\nLIMIT 20;\n```\n\n### 3. 2つのアプリをJOIN\n```sql\nSELECT\n  a.顧客No,\n  a.会社名,\n  b.案件No_ AS 案件No,\n  b.案件名,\n  b.商談フェーズ\nFROM APP4148 AS a\nINNER JOIN APP4149 AS b\n  ON a.顧客No = b.顧客No_;\n```\n\n### 4. 結果をエクスポート\n- JSON\n- CSV\n\n# cli-ksql のしくみ（内部構成）\n\n`cli-ksql` は、SQL文字列を AST(Abstract Syntax Tree) に変換し、kintone API 実行計画へ落として実行する構成です。  \n実装上は `src/cli`（CLI層）と `src/execute.ts`（実行エンジン）を中心に動きます。\n\n## 全体構成\n\n```mermaid\nflowchart LR\n  U[\"User (CLI / REPL)\"] --\u003e C[\"src/cli/index.ts\\n引数解析・設定読込・ガード\"]\n  C --\u003e P[\"normalizeSqlAppProfiles()\\nAPP@profile 正規化\"]\n  P --\u003e E[\"execute(sql, client, options)\\nsrc/execute.ts\"]\n\n  E --\u003e L[\"Lexer\\nsrc/lexer/lexer.ts\"]\n  L --\u003e R[\"Parser\\nsrc/parser/parser.ts\"]\n  R --\u003e A[\"AST (Statement)\\nsrc/types/ast.ts\"]\n\n  A --\u003e M[\"Select mode 判定\\nresolveSelectMode()\"]\n  M --\u003e S[\"SIMPLE path\\nselectToKintone / whereToKintone\"]\n  M --\u003e F[\"FULL_SCAN path\\nfetchAll + runFullScan\"]\n\n  S --\u003e K[\"KintoneClient\\n(get/post/put/delete/getApps/getFields)\"]\n  F --\u003e K\n\n  K --\u003e N[\"src/cli/nodeKintoneClient.ts\\n/k/v1 or /k/guest/\u003cid\u003e/v1 呼び出し\"]\n  N --\u003e API[\"kintone REST API\"]\n\n  E --\u003e O[\"formatDisplayText()\\n表示整形\"]\n  O --\u003e OUT[\"table / json / jsonl / csv / --output\"]\n```\n\n## SELECT 実行フロー\n\n```mermaid\nflowchart TD\n  Q[\"SQL 入力\"] --\u003e X[\"parseSql()\"]\n  X --\u003e Y{\"FROM 省略?\"}\n  Y -- \"yes\" --\u003e Z[\"executeNoFromSelect()\\n例: SELECT 'ABC' as a;\"]\n  Y -- \"no\" --\u003e W[\"resolveSelectMode()\"]\n\n  W --\u003e T{\"mode\"}\n  T -- \"SIMPLE\" --\u003e S1[\"executeSimpleSelect()\\n可能なら kintone クエリへ変換\"]\n  T -- \"FULL_SCAN\" --\u003e F1[\"executeFullScanSelect()\\n全件取得して JS 評価\"]\n\n  S1 --\u003e G1[\"client.getRecords() / fetchAll()\"]\n  F1 --\u003e G2[\"fetchAll() -\u003e runFullScan()\"]\n\n  G1 --\u003e R1[\"project/order/limit\"]\n  G2 --\u003e R1\n  Z --\u003e R1\n  R1 --\u003e RES[\"SelectResult rows/columns\"]\n```\n\n## モジュールごとの役割\n\n- `src/cli/index.ts`\n  - `parseArgs()` で引数を解析\n  - config/profile を解決\n  - `normalizeSqlAppProfiles()` で `APP@profile` を正規化\n  - DML ガード（`--allow-dml`, `--allow-without-where`, `--dml-max-rows`）\n- `src/execute.ts`\n  - `execute()` が文種別ごとに処理をルーティング\n  - `SELECT/UNION/WITH/INSERT/UPDATE/DELETE/UPSERT/REORDER/SHOW APPS/DESCRIBE/EXPLAIN` を処理\n- `src/converter/*`\n  - SQL AST を kintone API パラメータへ変換\n- `src/engine/*`\n  - FULL_SCAN 時の式評価、WHERE 評価、JOIN/GROUP BY/HAVING/ORDER BY 処理\n- `src/api/fetchAll.ts`\n  - ページングしながら全件取得\n- `src/cli/nodeKintoneClient.ts`\n  - Node.js から kintone REST API を呼び出す薄いクライアント\n\n## `APP@profile` の流れ\n\n1. CLI で SQL 中の `APP4148@dev` などを検出  \n2. `@profile` を外した正規化SQLを実行エンジンへ渡す  \n3. 実行時の app-\u003eprofile 束縛を保持し、対応する接続先 client に振り分ける  \n4. 同一SQL内で同一APPに複数profileが混在しても、内部仮想 appId で衝突回避\n\n## まとめ\n\n- CLI は「入力と実行環境の解決」\n- execute は「SQLの意味解釈と実行制御」\n- converter/engine は「kintone API に寄せる層」と「JSで補完する層」\n\nという分担です。  \nこの分離によって、プラグインUIとCLIが同じコアロジックを共有できます。\n","coediting":false,"comments_count":0,"created_at":"2026-04-08T09:30:09+09:00","group":null,"id":"a2f26c8931c4802ad1b7","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"SQL","versions":[]},{"name":"kintone","versions":[]},{"name":"codex","versions":[]}],"title":"kintone でSQL実行しよう その１０（cli対応）","updated_at":"2026-04-08T11:31:30+09:00","url":"https://qiita.com/rex0220/items/a2f26c8931c4802ad1b7","user":{"description":"","facebook_id":"","followees_count":0,"followers_count":150,"github_login_name":"rex0220","id":"rex0220","items_count":594,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":100572,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/100572/profile-images/1473708137","team_only":false,"twitter_screen_name":"rex02201","website_url":"https://rex0220.stores.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:123\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F9b1f73c0-45c4-4192-a605-b41081a11cb4.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=ee5f3dad85a64f33fee89ab507e21d43\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F9b1f73c0-45c4-4192-a605-b41081a11cb4.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=ee5f3dad85a64f33fee89ab507e21d43\" alt=\"day007.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F9b1f73c0-45c4-4192-a605-b41081a11cb4.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=ac175b40397045f54b1aa1c76c6ea718 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/9b1f73c0-45c4-4192-a605-b41081a11cb4.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-4:75\"\u003e面倒解決エンジニアの森田ユウゴです。\u003cbr\u003e\n台湾からお届けする「#kintone100日チャレンジ」の7日目。\u003c/p\u003e\n\u003cp data-sourcepos=\"6:1-7:68\"\u003e気が付けば1週間経っていました。\u003cbr\u003e\nこの1週間は朝からkintoneのことを考える生活です。\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-9:107\"\u003e👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジの概要はこちら\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"11:1-11:244\"\u003e本日は、【レガシーシステムからの移行を検討している情シス担当者や入力オペレーター】向けの「\u003cstrong\u003e【カスタムショートカットキー設定プラグイン】\u003c/strong\u003e」を開発しようとしました。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"13:1-13:87\"\u003e\n\u003cspan id=\"カスタムショートカットキー設定プラグインについて\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%82%AD%E3%83%BC%E8%A8%AD%E5%AE%9A%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e「【カスタムショートカットキー設定プラグイン】」について\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"14:1-14:75\"\u003e\n\u003cspan id=\"-なぜ開発したか現場の課題とベネフィット\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%AA%E3%81%9C%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E3%81%8B%E7%8F%BE%E5%A0%B4%E3%81%AE%E8%AA%B2%E9%A1%8C%E3%81%A8%E3%83%99%E3%83%8D%E3%83%95%E3%82%A3%E3%83%83%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🎯 なぜ開発したか？（現場の課題とベネフィット）\u003c/h3\u003e\n\u003cul data-sourcepos=\"15:1-17:0\"\u003e\n\u003cli data-sourcepos=\"15:1-15:433\"\u003e\n\u003cstrong\u003e現場の「不」:\u003c/strong\u003e 自治体や金融機関などのレガシーな専用システムでよく見かける「プログラムキーボード」。「F1で登録」「F2で照会」といった、キーボードのみで完結する高速な入力業務に慣れ親しんだ現場にとって、kintone移行時の「マウスへの持ち替え」は大きなストレスであり、作業効率低下の要因となります。\u003c/li\u003e\n\u003cli data-sourcepos=\"16:1-17:0\"\u003e\n\u003cstrong\u003e導入後の世界（ベネフィット）:\u003c/strong\u003e 画面（一覧・詳細・追加）ごとに、特定の機能（保存、編集、検索など）を任意のキーに割り当てることで、マウスを使わずにキーボード操作だけで業務が完結。入力スピードの維持・向上を目指します（…という想定でした）。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"18:1-18:50\"\u003e\n\u003cspan id=\"-これで出来ること機能概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%93%E3%82%8C%E3%81%A7%E5%87%BA%E6%9D%A5%E3%82%8B%E3%81%93%E3%81%A8%E6%A9%9F%E8%83%BD%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e✨ これで出来ること（機能概要）\u003c/h3\u003e\n\u003cp data-sourcepos=\"19:1-19:42\"\u003eまずはこちらをご覧ください。\u003c/p\u003e\n\u003ciframe width=\"100%\" height=\"315\" src=\"https://www.youtube.com/embed/MEddkWVi3wo\" frameborder=\"0\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cul data-sourcepos=\"24:1-27:0\"\u003e\n\u003cli data-sourcepos=\"24:1-24:365\"\u003e\n\u003cstrong\u003e【画面ごとのキーカスタマイズ】:\u003c/strong\u003e レコード一覧、詳細・編集、レコード追加の各画面において、「新規」「編集」「保存」「次へ」といったアクションに対して、ShiftやCtrlキーを組み合わせた任意のショートカットキーをプラグイン設定画面から割り当て可能です。\u003c/li\u003e\n\u003cli data-sourcepos=\"25:1-25:345\"\u003e\n\u003cstrong\u003e【ナビゲーションバーとヘルプ機能】:\u003c/strong\u003e 画面上部に現在有効なショートカットキーのナビゲーションバーを表示します。また、「?」キーを押すことで、現在設定されているショートカットの一覧をポップアップ（ヘルプオーバーレイ）で確認できます。\u003c/li\u003e\n\u003cli data-sourcepos=\"26:1-27:0\"\u003e\n\u003cstrong\u003e【入力中の誤爆防止】:\u003c/strong\u003e テキストボックスなどの入力フィールドにフォーカスが当たっている時は、ショートカットの発動を無視するように制御し、意図しない画面遷移を防ぎます。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"28:1-28:10\"\u003e\n\u003cspan id=\"課題\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%AA%B2%E9%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e課題\u003c/h3\u003e\n\u003cp data-sourcepos=\"29:1-29:278\"\u003e正直に言います。\u003cstrong\u003e今回の開発は「失敗」です。\u003c/strong\u003e PoC（概念実証）の段階で、汎用的なプラグインとして実用に耐えうる品質に到達しないことが判明しました。現時点では下記のような課題が残っています。\u003c/p\u003e\n\u003cul data-sourcepos=\"31:1-38:0\"\u003e\n\u003cli data-sourcepos=\"31:1-32:712\"\u003e\n\u003cstrong\u003e【DOM操作への依存と「保存」の不具合】\u003c/strong\u003e\u003cbr\u003e\nAIに「このボタンのショートカットを作って」と指示した結果、出力されたコード（\u003ccode\u003edesktop.js\u003c/code\u003eの\u003ccode\u003eACTION_SELECTORS\u003c/code\u003e周辺）は、kintoneのHTMLクラス名を直接指定して無理やり\u003ccode\u003eclick()\u003c/code\u003eイベントを発火させる、非常に脆い実装でした。「アップデートでDOM構造が変わったら即死する」コードです。さらに、詳細画面の「保存」ボタンについては、この強制クリックによるイベント発火がkintone標準のバリデーションや保存処理とうまく連携できず、保存が効かないという致命的な不具合を抱えています（検証不足のまま壁にぶつかりました）。\u003c/li\u003e\n\u003cli data-sourcepos=\"33:1-34:235\"\u003e\n\u003cstrong\u003e【ネイティブショートカットの完全再現の壁】\u003c/strong\u003e\u003cbr\u003e\nkintone標準のショートカット機能（一覧画面での \u003ccode\u003ej\u003c/code\u003e や \u003ccode\u003ek\u003c/code\u003e によるレコード移動など）に相当する滑らかな動きを再現しきれていません。ここばかりは検証不足は否めない…。\u003c/li\u003e\n\u003cli data-sourcepos=\"35:1-38:0\"\u003e\n\u003cstrong\u003e【「専用キーボード完結」という要件の深さ】\u003c/strong\u003e\u003cbr\u003e\nそもそも、レガシーシステムの操作感をWeb（kintone）で真に再現しようとすると、単にボタンにキーを割り当てるだけでは不十分です。「フォーム入力時の緻密なTabキー移動制御」「印刷などのハードウェア連携」「特定業務のAPI呼び出し」など、業務に極めて密結合した作り込みが必要になります。汎用的なプラグインとして提供するには存在意義が弱く、個別のカスタマイズ開発でしか解決できない領域だと痛感しました。\u003cbr\u003e\nこの点からも、細かい課題解決をするまでもなく「存在意義が弱い」として、最低限のPoC状態で今日は完成としました。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"39:1-39:15\"\u003e\n\u003cspan id=\"さいごに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eさいごに\u003c/h2\u003e\n\u003cp data-sourcepos=\"41:1-41:27\"\u003e明日もお楽しみに！\u003c/p\u003e\n\u003cp data-sourcepos=\"43:1-45:180\"\u003e下記のブログもご覧ください！\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！\u003c/a\u003e\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/kintone-support-service-coconala/\" rel=\"nofollow noopener\" target=\"_blank\"\u003eココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"47:1-47:114\"\u003e2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\u003c/p\u003e\n\u003cblockquote class=\"twitter-tweet\"\u003e\n\u003cp\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e— 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003eApril 15, 2026\u003c/a\u003e\n\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\"\u003e\u003c/script\u003e\n","body":"![day007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/9b1f73c0-45c4-4192-a605-b41081a11cb4.png)\n\n面倒解決エンジニアの森田ユウゴです。\n台湾からお届けする「#kintone100日チャレンジ」の7日目。\n\n気が付けば1週間経っていました。\nこの1週間は朝からkintoneのことを考える生活です。\n\n👉 [#kintone100日チャレンジの概要はこちら](https://moritayugo.com/100days-of-kintone-hacks/)\n\n本日は、【レガシーシステムからの移行を検討している情シス担当者や入力オペレーター】向けの「**【カスタムショートカットキー設定プラグイン】**」を開発しようとしました。\n\n## 「【カスタムショートカットキー設定プラグイン】」について\n### 🎯 なぜ開発したか？（現場の課題とベネフィット）\n- **現場の「不」:** 自治体や金融機関などのレガシーな専用システムでよく見かける「プログラムキーボード」。「F1で登録」「F2で照会」といった、キーボードのみで完結する高速な入力業務に慣れ親しんだ現場にとって、kintone移行時の「マウスへの持ち替え」は大きなストレスであり、作業効率低下の要因となります。\n- **導入後の世界（ベネフィット）:** 画面（一覧・詳細・追加）ごとに、特定の機能（保存、編集、検索など）を任意のキーに割り当てることで、マウスを使わずにキーボード操作だけで業務が完結。入力スピードの維持・向上を目指します（…という想定でした）。\n\n### ✨ これで出来ること（機能概要）\nまずはこちらをご覧ください。\n\n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/MEddkWVi3wo\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\n\n- **【画面ごとのキーカスタマイズ】:** レコード一覧、詳細・編集、レコード追加の各画面において、「新規」「編集」「保存」「次へ」といったアクションに対して、ShiftやCtrlキーを組み合わせた任意のショートカットキーをプラグイン設定画面から割り当て可能です。\n- **【ナビゲーションバーとヘルプ機能】:** 画面上部に現在有効なショートカットキーのナビゲーションバーを表示します。また、「?」キーを押すことで、現在設定されているショートカットの一覧をポップアップ（ヘルプオーバーレイ）で確認できます。\n- **【入力中の誤爆防止】:** テキストボックスなどの入力フィールドにフォーカスが当たっている時は、ショートカットの発動を無視するように制御し、意図しない画面遷移を防ぎます。\n\n### 課題\n正直に言います。**今回の開発は「失敗」です。** PoC（概念実証）の段階で、汎用的なプラグインとして実用に耐えうる品質に到達しないことが判明しました。現時点では下記のような課題が残っています。\n\n- **【DOM操作への依存と「保存」の不具合】**\n  AIに「このボタンのショートカットを作って」と指示した結果、出力されたコード（`desktop.js`の`ACTION_SELECTORS`周辺）は、kintoneのHTMLクラス名を直接指定して無理やり`click()`イベントを発火させる、非常に脆い実装でした。「アップデートでDOM構造が変わったら即死する」コードです。さらに、詳細画面の「保存」ボタンについては、この強制クリックによるイベント発火がkintone標準のバリデーションや保存処理とうまく連携できず、保存が効かないという致命的な不具合を抱えています（検証不足のまま壁にぶつかりました）。\n- **【ネイティブショートカットの完全再現の壁】**\n  kintone標準のショートカット機能（一覧画面での `j` や `k` によるレコード移動など）に相当する滑らかな動きを再現しきれていません。ここばかりは検証不足は否めない…。\n- **【「専用キーボード完結」という要件の深さ】**\n  そもそも、レガシーシステムの操作感をWeb（kintone）で真に再現しようとすると、単にボタンにキーを割り当てるだけでは不十分です。「フォーム入力時の緻密なTabキー移動制御」「印刷などのハードウェア連携」「特定業務のAPI呼び出し」など、業務に極めて密結合した作り込みが必要になります。汎用的なプラグインとして提供するには存在意義が弱く、個別のカスタマイズ開発でしか解決できない領域だと痛感しました。\n  この点からも、細かい課題解決をするまでもなく「存在意義が弱い」として、最低限のPoC状態で今日は完成としました。\n\n## さいごに\n\n明日もお楽しみに！\n\n下記のブログもご覧ください！\n👉 [【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！](https://moritayugo.com/100days-of-kintone-hacks/)\n👉 [ココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！](https://moritayugo.com/kintone-support-service-coconala/)\n\n2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\n\u003cblockquote class=\"twitter-tweet\"\u003e\u003cp lang=\"ja\" dir=\"ltr\"\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e\u0026mdash; 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\"\u003eApril 15, 2026\u003c/a\u003e\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\n","coediting":false,"comments_count":0,"created_at":"2026-04-07T17:24:54+09:00","group":null,"id":"61ae3eb36a73b3896528","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"kintoneplugin","versions":[]},{"name":"バイブコーディング","versions":[]},{"name":"kintoneカスタマイズ","versions":[]},{"name":"kintone100日チャレンジ","versions":[]}],"title":"【#kintone100日チャレンジ】Day 7: 自治体や金融システム風のキーボード入力プラグインを作ってみたかった","updated_at":"2026-04-15T09:55:52+09:00","url":"https://qiita.com/majinalife/items/61ae3eb36a73b3896528","user":{"description":"台湾在住の「面倒解決エンジニア」です。\r\n#kintone #Anki Chrome拡張など得意分野です💻\r\nアプリデザインスペシャリスト(2025)\r\nカスタマイズスペシャリスト(2026) \r\nお仕事のご依頼を承っておりますのでお気軽にご相談ください！","facebook_id":"","followees_count":1,"followers_count":1,"github_login_name":null,"id":"majinalife","items_count":13,"linkedin_id":"","location":"台湾","name":"森田 ユウゴ","organization":"","permanent_id":3990248,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3990248/795e2d2e68ab72ba29dc3224f01546c658346fc2/large.png?1774234714","team_only":false,"twitter_screen_name":"majinalife_blog","website_url":"https://moritayugo.com/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-2:51\"\u003eはじめまして。\u003cbr\u003e\n業務改善エンジニアのこめまるです。\u003c/p\u003e\n\u003cp data-sourcepos=\"4:1-4:72\"\u003e業務効率化・自動化に関わる中で、よく出てくるのが\u003c/p\u003e\n\u003cul data-sourcepos=\"6:1-10:0\"\u003e\n\u003cli data-sourcepos=\"6:1-6:32\"\u003eこれはRPAでやるべきか\u003c/li\u003e\n\u003cli data-sourcepos=\"7:1-7:45\"\u003ekintoneで管理したほうがいいのか\u003c/li\u003e\n\u003cli data-sourcepos=\"8:1-8:40\"\u003ePower Platformが向いているのか\u003c/li\u003e\n\u003cli data-sourcepos=\"9:1-10:0\"\u003e生成AIを使うべきか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"11:1-11:54\"\u003eといった「手段の選び方」の悩みです。\u003c/p\u003e\n\u003cp data-sourcepos=\"13:1-14:114\"\u003e実際の現場では、最初から正解のツールが決まっていることは少なく、\u003cbr\u003e\n「何を解決したいのか」を整理したうえで手段を選ぶことが大切だと感じています。\u003c/p\u003e\n\u003cp data-sourcepos=\"16:1-16:114\"\u003eこの記事では、自分が業務改善を考えるときに見ているポイントを整理してみます。\u003c/p\u003e\n\u003cdiv data-sourcepos=\"18:1-25:3\" class=\"note info\"\u003e\n\u003cspan class=\"fa fa-fw fa-check-circle\"\u003e\u003c/span\u003e\u003cdiv\u003e\n\u003cp data-sourcepos=\"19:1-19:42\"\u003eこの記事はこんな人におすすめ\u003c/p\u003e\n\u003cul data-sourcepos=\"21:1-24:62\"\u003e\n\u003cli data-sourcepos=\"21:1-21:89\"\u003e業務改善したいけれど、どのツールを選べばよいか迷っている方\u003c/li\u003e\n\u003cli data-sourcepos=\"22:1-22:73\"\u003eRPA・kintone・Power Platform・生成AIの違いを整理したい方\u003c/li\u003e\n\u003cli data-sourcepos=\"23:1-23:68\"\u003e流行りではなく、目的ベースで手段を選びたい方\u003c/li\u003e\n\u003cli data-sourcepos=\"24:1-24:62\"\u003e現場に合った使い分けの考え方を知りたい方\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003ch2 data-sourcepos=\"27:1-27:54\"\u003e\n\u003cspan id=\"まずは何を改善したいかを分ける\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E3%81%AF%E4%BD%95%E3%82%92%E6%94%B9%E5%96%84%E3%81%97%E3%81%9F%E3%81%84%E3%81%8B%E3%82%92%E5%88%86%E3%81%91%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまずは「何を改善したいか」を分ける\u003c/h2\u003e\n\u003cp data-sourcepos=\"29:1-29:87\"\u003e業務改善といっても、中身はいくつかのパターンに分かれます。\u003c/p\u003e\n\u003cp data-sourcepos=\"31:1-31:45\"\u003eたとえば、次のようなものです。\u003c/p\u003e\n\u003cul data-sourcepos=\"33:1-38:0\"\u003e\n\u003cli data-sourcepos=\"33:1-33:44\"\u003e同じ操作を毎回繰り返している\u003c/li\u003e\n\u003cli data-sourcepos=\"34:1-34:26\"\u003e情報の転記が多い\u003c/li\u003e\n\u003cli data-sourcepos=\"35:1-35:44\"\u003e管理表がバラバラで探しにくい\u003c/li\u003e\n\u003cli data-sourcepos=\"36:1-36:50\"\u003eメールやPDFの内容を手入力している\u003c/li\u003e\n\u003cli data-sourcepos=\"37:1-38:0\"\u003e判断や文章作成に時間がかかっている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"39:1-39:72\"\u003eこの時点で、選ぶ手段の方向性がかなり変わります。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"41:1-41:33\"\u003e\n\u003cspan id=\"rpaが向いているケース\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#rpa%E3%81%8C%E5%90%91%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eRPAが向いているケース\u003c/h2\u003e\n\u003cp data-sourcepos=\"43:1-43:93\"\u003eRPAは、既存システムをまたいだ定型作業の自動化と相性が良いです。\u003c/p\u003e\n\u003cp data-sourcepos=\"45:1-45:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"47:1-51:0\"\u003e\n\u003cli data-sourcepos=\"47:1-47:70\"\u003eシステムAから情報を取得してシステムBへ入力する\u003c/li\u003e\n\u003cli data-sourcepos=\"48:1-48:68\"\u003eメール添付ファイルを保存して所定の処理をする\u003c/li\u003e\n\u003cli data-sourcepos=\"49:1-49:49\"\u003eExcelを読み込んでWeb画面に転記する\u003c/li\u003e\n\u003cli data-sourcepos=\"50:1-51:0\"\u003e毎日決まった手順で確認作業をする\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"52:1-52:60\"\u003eといった処理は、RPAで効果が出やすいです。\u003c/p\u003e\n\u003cp data-sourcepos=\"54:1-55:72\"\u003e一方で、ルールが曖昧だったり、画面変更の影響を受けやすい処理は運用負荷が上がりやすいので、\u003cbr\u003e\n「本当にRPAで持つべきか」は少し慎重に見ています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"57:1-57:37\"\u003e\n\u003cspan id=\"kintoneが向いているケース\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E3%81%8C%E5%90%91%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintoneが向いているケース\u003c/h2\u003e\n\u003cp data-sourcepos=\"59:1-59:76\"\u003ekintoneは、情報管理や業務フローの整理に向いています。\u003c/p\u003e\n\u003cp data-sourcepos=\"61:1-61:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"63:1-67:0\"\u003e\n\u003cli data-sourcepos=\"63:1-63:52\"\u003eExcelで管理している台帳をまとめたい\u003c/li\u003e\n\u003cli data-sourcepos=\"64:1-64:44\"\u003e担当ごとの属人化を減らしたい\u003c/li\u003e\n\u003cli data-sourcepos=\"65:1-65:53\"\u003e入力項目や進捗状況を見える化したい\u003c/li\u003e\n\u003cli data-sourcepos=\"66:1-67:0\"\u003e申請、承認、履歴管理を整えたい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"68:1-68:30\"\u003eといったケースです。\u003c/p\u003e\n\u003cp data-sourcepos=\"70:1-71:124\"\u003e単に今のExcelを置き換えるというより、\u003cbr\u003e\n「情報をどう持つと運用しやすいか」を考えると、kintoneの良さが出やすいと感じています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"73:1-73:44\"\u003e\n\u003cspan id=\"power-platformが向いているケース\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#power-platform%E3%81%8C%E5%90%91%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ePower Platformが向いているケース\u003c/h2\u003e\n\u003cp data-sourcepos=\"75:1-75:80\"\u003ePower Platformは、Microsoft製品との親和性が高いのが強みです。\u003c/p\u003e\n\u003cp data-sourcepos=\"77:1-77:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"79:1-84:0\"\u003e\n\u003cli data-sourcepos=\"79:1-79:9\"\u003eOutlook\u003c/li\u003e\n\u003cli data-sourcepos=\"80:1-80:7\"\u003eTeams\u003c/li\u003e\n\u003cli data-sourcepos=\"81:1-81:12\"\u003eSharePoint\u003c/li\u003e\n\u003cli data-sourcepos=\"82:1-82:7\"\u003eExcel\u003c/li\u003e\n\u003cli data-sourcepos=\"83:1-84:0\"\u003eForms\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"85:1-85:75\"\u003eなどと組み合わせたい場合は、かなり候補になります。\u003c/p\u003e\n\u003cp data-sourcepos=\"87:1-88:99\"\u003e業務の中でMicrosoft 365をすでに使っている場合、\u003cbr\u003e\nPower AutomateやPower Appsで比較的スムーズに仕組み化できることがあります。\u003c/p\u003e\n\u003cp data-sourcepos=\"90:1-90:135\"\u003e一方で、作る前に「誰が使うのか」「運用保守を誰が見るのか」は確認しておいたほうがよいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"92:1-92:38\"\u003e\n\u003cspan id=\"生成aiが向いているケース\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%94%9F%E6%88%90ai%E3%81%8C%E5%90%91%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e生成AIが向いているケース\u003c/h2\u003e\n\u003cp data-sourcepos=\"94:1-94:74\"\u003e生成AIは、判断補助や文章生成、情報整理に強いです。\u003c/p\u003e\n\u003cp data-sourcepos=\"96:1-96:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"98:1-103:0\"\u003e\n\u003cli data-sourcepos=\"98:1-98:44\"\u003eメールや議事録のたたき台作成\u003c/li\u003e\n\u003cli data-sourcepos=\"99:1-99:47\"\u003ePDFや文書から必要情報を抜き出す\u003c/li\u003e\n\u003cli data-sourcepos=\"100:1-100:29\"\u003e問い合わせ文の要約\u003c/li\u003e\n\u003cli data-sourcepos=\"101:1-101:26\"\u003e情報の分類や整理\u003c/li\u003e\n\u003cli data-sourcepos=\"102:1-103:0\"\u003e非定型な文章の読み取り補助\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"104:1-104:15\"\u003eなどです。\u003c/p\u003e\n\u003cp data-sourcepos=\"106:1-107:96\"\u003eただし、生成AIはそれ単体で完結するというより、\u003cbr\u003e\n既存の業務フローの一部に組み込むと効果が出やすいと感じています。\u003c/p\u003e\n\u003cp data-sourcepos=\"109:1-109:107\"\u003e「AIを使うこと」自体が目的になると、あまりうまくいかないことが多いです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"111:1-111:45\"\u003e\n\u003cspan id=\"実際は組み合わせることが多い\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E9%9A%9B%E3%81%AF%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E5%A4%9A%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実際は組み合わせることが多い\u003c/h2\u003e\n\u003cp data-sourcepos=\"113:1-113:94\"\u003e現場では、1つのツールだけで完結することはあまり多くありません。\u003c/p\u003e\n\u003cp data-sourcepos=\"115:1-115:15\"\u003eたとえば、\u003c/p\u003e\n\u003cul data-sourcepos=\"117:1-121:0\"\u003e\n\u003cli data-sourcepos=\"117:1-117:40\"\u003eOCRや生成AIで情報を抽出する\u003c/li\u003e\n\u003cli data-sourcepos=\"118:1-118:26\"\u003eRPAやAPIで連携する\u003c/li\u003e\n\u003cli data-sourcepos=\"119:1-119:24\"\u003ekintoneに登録する\u003c/li\u003e\n\u003cli data-sourcepos=\"120:1-121:0\"\u003ePower Automateで通知する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"122:1-122:81\"\u003eのように、役割を分けて組み合わせることがよくあります。\u003c/p\u003e\n\u003cp data-sourcepos=\"124:1-125:132\"\u003eそのため、最初からツールを決め打ちするより、\u003cbr\u003e\n「どこが人の負担になっているか」を見つけて、そこに合う手段を当てるほうが進めやすいです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"127:1-127:36\"\u003e\n\u003cspan id=\"自分がよく見るポイント\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%87%AA%E5%88%86%E3%81%8C%E3%82%88%E3%81%8F%E8%A6%8B%E3%82%8B%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e自分がよく見るポイント\u003c/h2\u003e\n\u003cp data-sourcepos=\"129:1-129:81\"\u003e業務改善を考えるときは、次のような点をよく見ています。\u003c/p\u003e\n\u003cul data-sourcepos=\"131:1-136:0\"\u003e\n\u003cli data-sourcepos=\"131:1-131:41\"\u003eその業務は定型か、非定型か\u003c/li\u003e\n\u003cli data-sourcepos=\"132:1-132:29\"\u003e入力や転記が多いか\u003c/li\u003e\n\u003cli data-sourcepos=\"133:1-133:53\"\u003e情報管理がバラバラになっていないか\u003c/li\u003e\n\u003cli data-sourcepos=\"134:1-134:44\"\u003e人の判断が必要な部分はどこか\u003c/li\u003e\n\u003cli data-sourcepos=\"135:1-136:0\"\u003e運用開始後に誰がメンテナンスするか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"137:1-137:105\"\u003e特に、作ることより「運用し続けられるか」のほうが大事だと思っています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"139:1-139:15\"\u003e\n\u003cspan id=\"おわりに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eおわりに\u003c/h2\u003e\n\u003cp data-sourcepos=\"141:1-142:99\"\u003e業務改善では、どのツールを使うかよりも、\u003cbr\u003e\nまず業務のどこに課題があるかを整理することが大切だと感じています。\u003c/p\u003e\n\u003cp data-sourcepos=\"144:1-145:51\"\u003eRPA、kintone、Power Platform、生成AIはどれも便利ですが、\u003cbr\u003e\n向いている場面はそれぞれ違います。\u003c/p\u003e\n\u003cp data-sourcepos=\"147:1-147:66\"\u003e今後は、今回書いた内容をもう少し具体化して、\u003c/p\u003e\n\u003cul data-sourcepos=\"149:1-152:0\"\u003e\n\u003cli data-sourcepos=\"149:1-149:35\"\u003eどういう時にRPAを選ぶか\u003c/li\u003e\n\u003cli data-sourcepos=\"150:1-150:54\"\u003ekintoneで整理したほうがいい業務の特徴\u003c/li\u003e\n\u003cli data-sourcepos=\"151:1-152:0\"\u003e生成AIを業務で使う時に気をつけていること\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"153:1-153:60\"\u003eなども整理して書いていければと思います。\u003c/p\u003e\n","body":"はじめまして。\n業務改善エンジニアのこめまるです。\n\n業務効率化・自動化に関わる中で、よく出てくるのが\n\n* これはRPAでやるべきか\n* kintoneで管理したほうがいいのか\n* Power Platformが向いているのか\n* 生成AIを使うべきか\n\nといった「手段の選び方」の悩みです。\n\n実際の現場では、最初から正解のツールが決まっていることは少なく、\n「何を解決したいのか」を整理したうえで手段を選ぶことが大切だと感じています。\n\nこの記事では、自分が業務改善を考えるときに見ているポイントを整理してみます。\n\n:::note info\nこの記事はこんな人におすすめ\n\n- 業務改善したいけれど、どのツールを選べばよいか迷っている方\n- RPA・kintone・Power Platform・生成AIの違いを整理したい方\n- 流行りではなく、目的ベースで手段を選びたい方\n- 現場に合った使い分けの考え方を知りたい方\n:::\n\n## まずは「何を改善したいか」を分ける\n\n業務改善といっても、中身はいくつかのパターンに分かれます。\n\nたとえば、次のようなものです。\n\n* 同じ操作を毎回繰り返している\n* 情報の転記が多い\n* 管理表がバラバラで探しにくい\n* メールやPDFの内容を手入力している\n* 判断や文章作成に時間がかかっている\n\nこの時点で、選ぶ手段の方向性がかなり変わります。\n\n## RPAが向いているケース\n\nRPAは、既存システムをまたいだ定型作業の自動化と相性が良いです。\n\nたとえば、\n\n* システムAから情報を取得してシステムBへ入力する\n* メール添付ファイルを保存して所定の処理をする\n* Excelを読み込んでWeb画面に転記する\n* 毎日決まった手順で確認作業をする\n\nといった処理は、RPAで効果が出やすいです。\n\n一方で、ルールが曖昧だったり、画面変更の影響を受けやすい処理は運用負荷が上がりやすいので、\n「本当にRPAで持つべきか」は少し慎重に見ています。\n\n## kintoneが向いているケース\n\nkintoneは、情報管理や業務フローの整理に向いています。\n\nたとえば、\n\n* Excelで管理している台帳をまとめたい\n* 担当ごとの属人化を減らしたい\n* 入力項目や進捗状況を見える化したい\n* 申請、承認、履歴管理を整えたい\n\nといったケースです。\n\n単に今のExcelを置き換えるというより、\n「情報をどう持つと運用しやすいか」を考えると、kintoneの良さが出やすいと感じています。\n\n## Power Platformが向いているケース\n\nPower Platformは、Microsoft製品との親和性が高いのが強みです。\n\nたとえば、\n\n* Outlook\n* Teams\n* SharePoint\n* Excel\n* Forms\n\nなどと組み合わせたい場合は、かなり候補になります。\n\n業務の中でMicrosoft 365をすでに使っている場合、\nPower AutomateやPower Appsで比較的スムーズに仕組み化できることがあります。\n\n一方で、作る前に「誰が使うのか」「運用保守を誰が見るのか」は確認しておいたほうがよいです。\n\n## 生成AIが向いているケース\n\n生成AIは、判断補助や文章生成、情報整理に強いです。\n\nたとえば、\n\n* メールや議事録のたたき台作成\n* PDFや文書から必要情報を抜き出す\n* 問い合わせ文の要約\n* 情報の分類や整理\n* 非定型な文章の読み取り補助\n\nなどです。\n\nただし、生成AIはそれ単体で完結するというより、\n既存の業務フローの一部に組み込むと効果が出やすいと感じています。\n\n「AIを使うこと」自体が目的になると、あまりうまくいかないことが多いです。\n\n## 実際は組み合わせることが多い\n\n現場では、1つのツールだけで完結することはあまり多くありません。\n\nたとえば、\n\n* OCRや生成AIで情報を抽出する\n* RPAやAPIで連携する\n* kintoneに登録する\n* Power Automateで通知する\n\nのように、役割を分けて組み合わせることがよくあります。\n\nそのため、最初からツールを決め打ちするより、\n「どこが人の負担になっているか」を見つけて、そこに合う手段を当てるほうが進めやすいです。\n\n## 自分がよく見るポイント\n\n業務改善を考えるときは、次のような点をよく見ています。\n\n* その業務は定型か、非定型か\n* 入力や転記が多いか\n* 情報管理がバラバラになっていないか\n* 人の判断が必要な部分はどこか\n* 運用開始後に誰がメンテナンスするか\n\n特に、作ることより「運用し続けられるか」のほうが大事だと思っています。\n\n## おわりに\n\n業務改善では、どのツールを使うかよりも、\nまず業務のどこに課題があるかを整理することが大切だと感じています。\n\nRPA、kintone、Power Platform、生成AIはどれも便利ですが、\n向いている場面はそれぞれ違います。\n\n今後は、今回書いた内容をもう少し具体化して、\n\n* どういう時にRPAを選ぶか\n* kintoneで整理したほうがいい業務の特徴\n* 生成AIを業務で使う時に気をつけていること\n\nなども整理して書いていければと思います。\n","coediting":false,"comments_count":0,"created_at":"2026-04-07T10:48:27+09:00","group":null,"id":"a0b56ff2b4fdd598bca7","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"業務改善","versions":[]},{"name":"RPA","versions":[]},{"name":"PowerPlatform","versions":[]},{"name":"生成AI","versions":[]}],"title":"業務改善で迷ったときの考え方｜RPA・kintone・Power Platform・生成AIの使い分け","updated_at":"2026-04-07T17:41:29+09:00","url":"https://qiita.com/komemaru/items/a0b56ff2b4fdd598bca7","user":{"description":"業務改善エンジニア／情報処理安全確保支援士。RPA、kintone、Power Platform、生成AIを活用した業務効率化に取り組んでいます。実務で得た知見や技術メモを発信しています。\r\n","facebook_id":"","followees_count":1,"followers_count":2,"github_login_name":null,"id":"komemaru","items_count":8,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":4401379,"profile_image_url":"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4401379/profile-images/1775526468","team_only":false,"twitter_screen_name":"komemaru_dx","website_url":""},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:123\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F1637e8c1-e2f9-4eab-8d87-ca36f839ecd1.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=896a40e797fd5c5fcd71044ce19e9911\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F1637e8c1-e2f9-4eab-8d87-ca36f839ecd1.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=896a40e797fd5c5fcd71044ce19e9911\" alt=\"day006.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3990248%2F1637e8c1-e2f9-4eab-8d87-ca36f839ecd1.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=9c465c8671d84471fc02307c2a5c948b 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/1637e8c1-e2f9-4eab-8d87-ca36f839ecd1.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-5:231\"\u003e面倒解決エンジニアの森田ユウゴです。\u003cbr\u003e\n台湾からお届けする「#kintone100日チャレンジ」の 6 日目。\u003cbr\u003e\n昨日作成した「\u003ca href=\"https://qiita.com/majinalife/items/a5a10d9ef3605cdfca26\" id=\"reference-20e00a169af9e2775658\"\u003ekintone Config Exporter...kin for Git\u003c/a\u003e」がかなり有用と自我自賛しており、今日は少し捻ったテーマに挑戦してみました。\u003c/p\u003e\n\u003cp data-sourcepos=\"7:1-7:106\"\u003e本日は結果として「\u003cstrong\u003eマウスジェスチャー実行プラグイン\u003c/strong\u003e」を開発しました！\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-9:114\"\u003e今回は「こんなはずじゃなかった…」という盛大な軌道修正の記録も兼ねています。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"11:1-11:69\"\u003e\n\u003cspan id=\"マウスジェスチャー実行プラグインについて\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%9E%E3%82%A6%E3%82%B9%E3%82%B8%E3%82%A7%E3%82%B9%E3%83%81%E3%83%A3%E3%83%BC%E5%AE%9F%E8%A1%8C%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e「マウスジェスチャー実行プラグイン」について\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"12:1-12:75\"\u003e\n\u003cspan id=\"-なぜ開発したか現場の課題とベネフィット\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%AA%E3%81%9C%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E3%81%8B%E7%8F%BE%E5%A0%B4%E3%81%AE%E8%AA%B2%E9%A1%8C%E3%81%A8%E3%83%99%E3%83%8D%E3%83%95%E3%82%A3%E3%83%83%E3%83%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e🎯 なぜ開発したか？（現場の課題とベネフィット）\u003c/h3\u003e\n\u003cul data-sourcepos=\"13:1-16:0\"\u003e\n\u003cli data-sourcepos=\"13:1-13:429\"\u003e\n\u003cstrong\u003e現場の「不」:\u003c/strong\u003e kintoneには「e」で編集、「c」でレコード追加などの便利なショートカットキーがあります。しかし、**「マウスを持った手をキーボードに戻すのすら面倒くさい！」**という極度の面倒くさがり（私です）のために、右クリックジェスチャーでこれらのショートカットを呼び出せないかと考えました。\u003c/li\u003e\n\u003cli data-sourcepos=\"14:1-16:0\"\u003e\n\u003cstrong\u003e導入後の世界（ベネフィット）:\u003c/strong\u003e 結論から言うと、\u003cstrong\u003e当初の野望は失敗に終わりました\u003c/strong\u003e。妥協の産物としてブラウザ操作（戻る・進む・更新）のみの実装となりました。\u003cbr\u003e\n前向きにプレゼンするのなら、「社内セキュリティポリシーで便利なChrome拡張機能の一律導入が禁止されている」といったガチガチの環境でも、kintoneアプリ単体で直感的なマウス操作を実現し、日々の無駄なマウス移動を削減できます。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"17:1-17:50\"\u003e\n\u003cspan id=\"-これで出来ること機能概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#-%E3%81%93%E3%82%8C%E3%81%A7%E5%87%BA%E6%9D%A5%E3%82%8B%E3%81%93%E3%81%A8%E6%A9%9F%E8%83%BD%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e✨ これで出来ること（機能概要）\u003c/h3\u003e\n\u003cp data-sourcepos=\"18:1-18:42\"\u003eまずはこちらをご覧ください。\u003c/p\u003e\n\u003ciframe width=\"100%\" height=\"315\" src=\"https://www.youtube.com/embed/ZquTbd824Mk\" frameborder=\"0\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cul data-sourcepos=\"22:1-25:0\"\u003e\n\u003cli data-sourcepos=\"22:1-22:222\"\u003e\n\u003cstrong\u003e右クリック＋ドラッグでの直感操作:\u003c/strong\u003e 上下左右の4方向へのドラッグに対して、「ページを更新」「戻る」「進む」「何もしない」のアクションを実行できます。\u003c/li\u003e\n\u003cli data-sourcepos=\"23:1-23:325\"\u003e\n\u003cstrong\u003eジェスチャー軌跡のビジュアルフィードバック:\u003c/strong\u003e 右クリックを押しながらマウスを動かすと、画面上に青いグラデーションの軌跡ラインがリアルタイムで描画されます。AIがサクッと書いてくれた割に、操作感が良くて気に入っています。\u003c/li\u003e\n\u003cli data-sourcepos=\"24:1-25:0\"\u003e\n\u003cstrong\u003e画面ごとの個別アクション設定:\u003c/strong\u003e レコード一覧、詳細、編集、追加の4つの画面それぞれで、方向ごとの挙動をプラグイン設定画面から柔軟にカスタマイズ可能です。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"26:1-26:10\"\u003e\n\u003cspan id=\"課題\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%AA%B2%E9%A1%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e課題\u003c/h3\u003e\n\u003cp data-sourcepos=\"27:1-27:84\"\u003e今回は開発の過程でぶつかった壁そのものが最大の課題です。\u003c/p\u003e\n\u003cul data-sourcepos=\"29:1-34:0\"\u003e\n\u003cli data-sourcepos=\"29:1-30:846\"\u003e\n\u003cstrong\u003e【敗北宣言】kintone標準ショートカットはマウスで再現できなかった\u003c/strong\u003e\u003cbr\u003e\n  当初、AIへのプロンプトでは「右クリックジェスチャーで、kintone標準のキーボードショートカット（eキーなど）を擬似的に発火させてほしい」と指示し、AIも素直に\u003ccode\u003eKeyboardEvent\u003c/code\u003eを発火させるコードをドヤ顔で出力してきました。しかし、動きません。理由は\u003cstrong\u003e現代のブラウザセキュリティの壁\u003c/strong\u003eです。JavaScriptから生成された擬似的なキーイベントは、セキュリティ上の理由から（イベントの\u003ccode\u003eisTrusted\u003c/code\u003eプロパティが\u003ccode\u003efalse\u003c/code\u003eになるため）、ブラウザやkintone本体に「本物のユーザーのキー入力」として認識されず、アクションが発火しないのです。この制約を突破できず、今回は確実なWindow操作である「戻る・更新」等に留めました。\u003c/li\u003e\n\u003cli data-sourcepos=\"31:1-34:0\"\u003e\n\u003cstrong\u003e「これ、Chromeの拡張機能でよくない？」という賢者タイム\u003c/strong\u003e\u003cbr\u003e\n  妥協してブラウザの「戻る・進む」を実装している最中、「あれ、これわざわざkintoneのプラグインで作らなくても、汎用的なマウスジェスチャーのChrome拡張機能を作った方が良くないか？」という根源的なツッコミが脳内をよぎりました。\u003cbr\u003e\n今回は「拡張機能が禁止されている企業向け」という大義名分でカバーしていますが、当初の「kintoneならではの課題を解決する」という具体性からは少し遠のいてしまいました。とはいえ、JavaScriptの操作次第でkintoneのUX（ユーザー体験）をここまで根本からいじれるという可能性に改めて気づけたのは、大きな収穫でした。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"35:1-35:15\"\u003e\n\u003cspan id=\"さいごに\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eさいごに\u003c/h2\u003e\n\u003cp data-sourcepos=\"37:1-37:27\"\u003e明日もお楽しみに！\u003c/p\u003e\n\u003cp data-sourcepos=\"39:1-41:180\"\u003e下記のブログもご覧ください！\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/100days-of-kintone-hacks/\" rel=\"nofollow noopener\" target=\"_blank\"\u003e【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！\u003c/a\u003e\u003cbr\u003e\n👉 \u003ca href=\"https://moritayugo.com/kintone-support-service-coconala/\" rel=\"nofollow noopener\" target=\"_blank\"\u003eココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"43:1-43:114\"\u003e2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\u003c/p\u003e\n\u003cblockquote class=\"twitter-tweet\"\u003e\n\u003cp\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e— 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\" rel=\"nofollow noopener\" target=\"_blank\"\u003eApril 15, 2026\u003c/a\u003e\n\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\"\u003e\u003c/script\u003e\n","body":"![day006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990248/1637e8c1-e2f9-4eab-8d87-ca36f839ecd1.png)\n\n面倒解決エンジニアの森田ユウゴです。\n台湾からお届けする「#kintone100日チャレンジ」の 6 日目。\n昨日作成した「[kintone Config Exporter...kin for Git](https://qiita.com/majinalife/items/a5a10d9ef3605cdfca26)」がかなり有用と自我自賛しており、今日は少し捻ったテーマに挑戦してみました。\n\n本日は結果として「**マウスジェスチャー実行プラグイン**」を開発しました！\n\n今回は「こんなはずじゃなかった…」という盛大な軌道修正の記録も兼ねています。\n\n## 「マウスジェスチャー実行プラグイン」について\n### 🎯 なぜ開発したか？（現場の課題とベネフィット）\n- **現場の「不」:** kintoneには「e」で編集、「c」でレコード追加などの便利なショートカットキーがあります。しかし、**「マウスを持った手をキーボードに戻すのすら面倒くさい！」**という極度の面倒くさがり（私です）のために、右クリックジェスチャーでこれらのショートカットを呼び出せないかと考えました。\n- **導入後の世界（ベネフィット）:** 結論から言うと、**当初の野望は失敗に終わりました**。妥協の産物としてブラウザ操作（戻る・進む・更新）のみの実装となりました。\n  前向きにプレゼンするのなら、「社内セキュリティポリシーで便利なChrome拡張機能の一律導入が禁止されている」といったガチガチの環境でも、kintoneアプリ単体で直感的なマウス操作を実現し、日々の無駄なマウス移動を削減できます。\n\n### ✨ これで出来ること（機能概要）\nまずはこちらをご覧ください。\n\n\u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/ZquTbd824Mk\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" loading=\"lazy\" allowfullscreen\u003e\u003c/iframe\u003e\n\n- **右クリック＋ドラッグでの直感操作:** 上下左右の4方向へのドラッグに対して、「ページを更新」「戻る」「進む」「何もしない」のアクションを実行できます。\n- **ジェスチャー軌跡のビジュアルフィードバック:** 右クリックを押しながらマウスを動かすと、画面上に青いグラデーションの軌跡ラインがリアルタイムで描画されます。AIがサクッと書いてくれた割に、操作感が良くて気に入っています。\n- **画面ごとの個別アクション設定:** レコード一覧、詳細、編集、追加の4つの画面それぞれで、方向ごとの挙動をプラグイン設定画面から柔軟にカスタマイズ可能です。\n\n### 課題\n今回は開発の過程でぶつかった壁そのものが最大の課題です。\n\n- **【敗北宣言】kintone標準ショートカットはマウスで再現できなかった**\n  当初、AIへのプロンプトでは「右クリックジェスチャーで、kintone標準のキーボードショートカット（eキーなど）を擬似的に発火させてほしい」と指示し、AIも素直に`KeyboardEvent`を発火させるコードをドヤ顔で出力してきました。しかし、動きません。理由は**現代のブラウザセキュリティの壁**です。JavaScriptから生成された擬似的なキーイベントは、セキュリティ上の理由から（イベントの`isTrusted`プロパティが`false`になるため）、ブラウザやkintone本体に「本物のユーザーのキー入力」として認識されず、アクションが発火しないのです。この制約を突破できず、今回は確実なWindow操作である「戻る・更新」等に留めました。\n- **「これ、Chromeの拡張機能でよくない？」という賢者タイム**\n  妥協してブラウザの「戻る・進む」を実装している最中、「あれ、これわざわざkintoneのプラグインで作らなくても、汎用的なマウスジェスチャーのChrome拡張機能を作った方が良くないか？」という根源的なツッコミが脳内をよぎりました。\n  今回は「拡張機能が禁止されている企業向け」という大義名分でカバーしていますが、当初の「kintoneならではの課題を解決する」という具体性からは少し遠のいてしまいました。とはいえ、JavaScriptの操作次第でkintoneのUX（ユーザー体験）をここまで根本からいじれるという可能性に改めて気づけたのは、大きな収穫でした。\n\n## さいごに\n\n明日もお楽しみに！\n\n下記のブログもご覧ください！\n👉 [【#kintone100日連続チャレンジ】AIにkintoneカスタマイズを100%任せたらどこまでいけるか？現役フリーランスの「100 Days of kintone Hacks」始動！](https://moritayugo.com/100days-of-kintone-hacks/)\n👉 [ココナラで「kintone有資格者が導入や運用の相談にのります」サービスを開始します！](https://moritayugo.com/kintone-support-service-coconala/)\n\n2026/4/15追記…下記の通り、ソースコードとプロンプトについては公開を停止します。\n\u003cblockquote class=\"twitter-tweet\"\u003e\u003cp lang=\"ja\" dir=\"ltr\"\u003e\u003ca href=\"https://twitter.com/hashtag/kintone100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash\u0026amp;ref_src=twsrc%5Etfw\"\u003e#kintone100日チャレンジ\u003c/a\u003e 方針変更\u003cbr\u003e\u003cbr\u003eGithubの公開を停止します。\u003cbr\u003e\u003cbr\u003e免責に書いてきた「ほぼ100%AI生成」のリスクが伝わらず、いつの間にか本番適用される危うさを察知しました。\u003cbr\u003eまた、私が100％AIで納品する人材だと思われるのも本意ではないので…\u003cbr\u003e\u003cbr\u003e詳細は記事にて！👇\u003ca href=\"https://t.co/5etpecPA8A\"\u003ehttps://t.co/5etpecPA8A\u003c/a\u003e\u003c/p\u003e\u0026mdash; 森田ユウゴ@マジナライフ (@majinalife_blog) \u003ca href=\"https://twitter.com/majinalife_blog/status/2044215277525840044?ref_src=twsrc%5Etfw\"\u003eApril 15, 2026\u003c/a\u003e\u003c/blockquote\u003e \u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\n","coediting":false,"comments_count":0,"created_at":"2026-04-06T16:00:03+09:00","group":null,"id":"0919fd6a30865d7a296c","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]},{"name":"kintoneplugin","versions":[]},{"name":"バイブコーディング","versions":[]},{"name":"kintoneカスタマイズ","versions":[]},{"name":"kintone100日チャレンジ","versions":[]}],"title":"【#kintone100日チャレンジ】Day 6: kintoneでマウスジェスチャーを出来るプラグインを作ってみた","updated_at":"2026-04-15T09:55:52+09:00","url":"https://qiita.com/majinalife/items/0919fd6a30865d7a296c","user":{"description":"台湾在住の「面倒解決エンジニア」です。\r\n#kintone #Anki Chrome拡張など得意分野です💻\r\nアプリデザインスペシャリスト(2025)\r\nカスタマイズスペシャリスト(2026) \r\nお仕事のご依頼を承っておりますのでお気軽にご相談ください！","facebook_id":"","followees_count":1,"followers_count":1,"github_login_name":null,"id":"majinalife","items_count":13,"linkedin_id":"","location":"台湾","name":"森田 ユウゴ","organization":"","permanent_id":3990248,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3990248/795e2d2e68ab72ba29dc3224f01546c658346fc2/large.png?1774234714","team_only":false,"twitter_screen_name":"majinalife_blog","website_url":"https://moritayugo.com/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:134\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/438587c27dc51d109415\" id=\"reference-4f1bfb6dbe9a3f9fab92\"\u003ekintone でSQL実行しよう その８（しくみ解説）\u003c/a\u003eの続きです。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"3:1-3:8\"\u003e\n\u003cspan id=\"概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e概要\u003c/h1\u003e\n\u003cp data-sourcepos=\"5:1-5:244\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/bfb0149b57c5da9b4a2f\" id=\"reference-ba7700a6aabe413757e8\"\u003erex0220 kSQL 顧客ランク別集計\u003c/a\u003eの EXPAIN（実行計画）をみたら、全項目取得となっていたので必要な項目のみ取得するように改善してみました。\u003c/p\u003e\n\u003cul data-sourcepos=\"8:1-9:0\"\u003e\n\u003cli data-sourcepos=\"8:1-9:0\"\u003e変更前：全フィールド取得\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"10:1-10:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F15c31b0c-b1bb-416b-8212-ef43d01e3d96.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=a7a16b093e436f92e660cf2b62fa84e0\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F15c31b0c-b1bb-416b-8212-ef43d01e3d96.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=a7a16b093e436f92e660cf2b62fa84e0\" alt=\"2026-04-06_11h48_59.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F15c31b0c-b1bb-416b-8212-ef43d01e3d96.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=d580ce12cf599fe7dcb24c7876299ebf 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/15c31b0c-b1bb-416b-8212-ef43d01e3d96.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"12:1-13:0\"\u003e\n\u003cli data-sourcepos=\"12:1-13:0\"\u003e変更後：SQLで利用するフィールド取得\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"14:1-14:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F9e9cc866-1cb0-474c-9c8c-17a8b650c1f9.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=cd1af3cf2ef6f02fcc5232248545d85d\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F9e9cc866-1cb0-474c-9c8c-17a8b650c1f9.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=cd1af3cf2ef6f02fcc5232248545d85d\" alt=\"2026-04-06_12h07_36.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F9e9cc866-1cb0-474c-9c8c-17a8b650c1f9.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=cfae9f135a6bca3a7dfffe45c933d810 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/9e9cc866-1cb0-474c-9c8c-17a8b650c1f9.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"16:1-16:20\"\u003e\n\u003cspan id=\"rest-api-の結果\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#rest-api-%E3%81%AE%E7%B5%90%E6%9E%9C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eREST API の結果\u003c/h1\u003e\n\u003cp data-sourcepos=\"18:1-18:124\"\u003eブラウザーの Network で REST API の結果をみると、確かに必要フィールドのみ取得しています。\u003c/p\u003e\n\u003cul data-sourcepos=\"20:1-21:0\"\u003e\n\u003cli data-sourcepos=\"20:1-21:0\"\u003e顧客管理アプリ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"22:1-22:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F902188fa-dc93-4459-b6dd-23299f30dbe3.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=6a7052c6e32a5c6c1ff89f4dda4d517a\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F902188fa-dc93-4459-b6dd-23299f30dbe3.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=6a7052c6e32a5c6c1ff89f4dda4d517a\" alt=\"2026-04-06_12h07_15.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F902188fa-dc93-4459-b6dd-23299f30dbe3.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=1333f2a46b899d838e63a8099bd20f7b 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/902188fa-dc93-4459-b6dd-23299f30dbe3.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"24:1-25:0\"\u003e\n\u003cli data-sourcepos=\"24:1-25:0\"\u003e案件管理アプリ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"26:1-26:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fc6b2abc7-9f1e-465c-aaf1-3244022e9675.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=a3224e6d7b11c9a1de26d126f7750437\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fc6b2abc7-9f1e-465c-aaf1-3244022e9675.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=a3224e6d7b11c9a1de26d126f7750437\" alt=\"2026-04-06_12h06_57.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fc6b2abc7-9f1e-465c-aaf1-3244022e9675.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=2e691c741be29e617f1189f7ebd80199 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c6b2abc7-9f1e-465c-aaf1-3244022e9675.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"28:1-28:63\"\u003e\n\u003cspan id=\"full_scan時の必要フィールド取得最適化-実装案\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#full_scan%E6%99%82%E3%81%AE%E5%BF%85%E8%A6%81%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%8F%96%E5%BE%97%E6%9C%80%E9%81%A9%E5%8C%96-%E5%AE%9F%E8%A3%85%E6%A1%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eFULL_SCAN時の必要フィールド取得最適化 実装案\u003c/h1\u003e\n\u003cp data-sourcepos=\"30:1-31:78\"\u003eCodex の実装案です。\u003cbr\u003e\n何回かやり取りをして、実装案をまとめてもらいました。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"33:1-51:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e下記のSQL で、全フィールド取得している\nパフォーマス改善のため、必要な項目のみ取得するようにできるか、検討して\n\nSELECT a.顧客ランク AS 顧客ランク, FORMAT(SUM(b.合計費用),'#,##0') AS 合計\nFROM APP89 AS a\nINNER JOIN APP88 AS b ON a.顧客名 = b.顧客名\nGROUP BY a.顧客ランク\n\n\n1\tmode: FULL_SCAN\n2\treason: JOIN あり, GROUP BY あり\n3\tapp: APP89 AS a (89)\n4\tkintone query: (全件取得)\n5\tfields: (全フィールド)\n6\tJOIN: APP88 AS b (88)\n7\tkintone query: (全件取得)\n8\tfields: (全フィールド)\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"52:1-54:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eサブテーブルを SELECT する場合は、$id なども必要になるが、影響は？\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"55:1-57:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eWIDTH の場合は？\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"58:1-60:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003eサブクエリーは？\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"61:1-63:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e実装案をマークダウンファイルに作成\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"64:1-64:3\"\u003e...\u003c/p\u003e\n\u003ch2 data-sourcepos=\"66:1-66:9\"\u003e\n\u003cspan id=\"背景\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%83%8C%E6%99%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e背景\u003c/h2\u003e\n\u003cp data-sourcepos=\"67:1-68:217\"\u003e現状の \u003ccode\u003eFULL_SCAN\u003c/code\u003e では \u003ccode\u003efetchAll(..., fields: [])\u003c/code\u003e を使用しており、常に全フィールド取得になる。\u003cbr\u003e\nJOIN / GROUP BY / HAVING / DISTINCT / ORDER BY を含むクエリでは全件取得が必要なケースが多いが、全フィールド取得は不要な通信量・メモリ使用・JS処理コストを増やす。\u003c/p\u003e\n\u003cp data-sourcepos=\"70:1-70:10\"\u003e対象例:\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"72:1-77:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFORMAT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eSUM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e合計費用\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"s1\"\u003e'#,##0'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"err\"\u003e合計\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP89\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\n\u003cspan class=\"k\"\u003eINNER\u003c/span\u003e \u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP88\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"k\"\u003eON\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\n\u003cspan class=\"k\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"79:1-79:57\"\u003eこの場合の必要フィールドは以下で十分。\u003c/p\u003e\n\u003cul data-sourcepos=\"80:1-82:0\"\u003e\n\u003cli data-sourcepos=\"80:1-80:42\"\u003eAPP89(a): \u003ccode\u003e顧客名\u003c/code\u003e, \u003ccode\u003e顧客ランク\u003c/code\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"81:1-82:0\"\u003eAPP88(b): \u003ccode\u003e顧客名\u003c/code\u003e, \u003ccode\u003e合計費用\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"83:1-83:9\"\u003e\n\u003cspan id=\"目的\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%9B%AE%E7%9A%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e目的\u003c/h2\u003e\n\u003cul data-sourcepos=\"84:1-87:0\"\u003e\n\u003cli data-sourcepos=\"84:1-84:95\"\u003eFULL_SCAN時の取得フィールドを「クエリ実行に必要な最小集合」にする\u003c/li\u003e\n\u003cli data-sourcepos=\"85:1-85:62\"\u003e結果互換性（既存SQLの実行結果）を維持する\u003c/li\u003e\n\u003cli data-sourcepos=\"86:1-87:0\"\u003eEXPLAIN表示を実取得フィールドと整合させる\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"88:1-88:12\"\u003e\n\u003cspan id=\"非目的\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E9%9D%9E%E7%9B%AE%E7%9A%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e非目的\u003c/h2\u003e\n\u003cul data-sourcepos=\"89:1-91:0\"\u003e\n\u003cli data-sourcepos=\"89:1-89:84\"\u003eFULL_SCAN自体をSIMPLE化する最適化（JOIN/GROUP BYの実行方式変更）\u003c/li\u003e\n\u003cli data-sourcepos=\"90:1-91:0\"\u003e相関サブクエリ対応の追加（現行仕様外）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"92:1-92:15\"\u003e\n\u003cspan id=\"期待効果\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%9C%9F%E5%BE%85%E5%8A%B9%E6%9E%9C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e期待効果\u003c/h2\u003e\n\u003cul data-sourcepos=\"93:1-96:0\"\u003e\n\u003cli data-sourcepos=\"93:1-93:51\"\u003eレコード1件あたりのペイロード削減\u003c/li\u003e\n\u003cli data-sourcepos=\"94:1-94:77\"\u003eJSONパース、flatten、JOIN時のオブジェクト結合コスト削減\u003c/li\u003e\n\u003cli data-sourcepos=\"95:1-96:0\"\u003eメモリ使用量削減\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"97:1-97:101\"\u003e注: 取得件数は変わらないため、APIページ数（呼び出し回数）は基本不変。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"99:1-99:36\"\u003e\n\u003cspan id=\"現状実装のボトルネック\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%8F%BE%E7%8A%B6%E5%AE%9F%E8%A3%85%E3%81%AE%E3%83%9C%E3%83%88%E3%83%AB%E3%83%8D%E3%83%83%E3%82%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e現状実装のボトルネック\u003c/h2\u003e\n\u003cul data-sourcepos=\"100:1-103:0\"\u003e\n\u003cli data-sourcepos=\"100:1-100:79\"\u003e\n\u003ccode\u003esrc/execute.ts\u003c/code\u003e の \u003ccode\u003efetchTableRecordsForFullScan()\u003c/code\u003e で \u003ccode\u003efields: []\u003c/code\u003e 固定\u003c/li\u003e\n\u003cli data-sourcepos=\"101:1-101:94\"\u003e\n\u003ccode\u003esrc/converter/selectToKintone.ts\u003c/code\u003e の \u003ccode\u003eselectToFetchAllParams()\u003c/code\u003e が \u003ccode\u003efields: []\u003c/code\u003e を返す\u003c/li\u003e\n\u003cli data-sourcepos=\"102:1-103:0\"\u003e\n\u003ccode\u003eEXPLAIN\u003c/code\u003e の FULL_SCAN表示が常に \u003ccode\u003e(全フィールド)\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"104:1-104:30\"\u003e\n\u003cspan id=\"提案アーキテクチャ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%8F%90%E6%A1%88%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e提案アーキテクチャ\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"106:1-106:64\"\u003e\n\u003cspan id=\"1-テーブル別の必要フィールド収集器を追加\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E5%88%A5%E3%81%AE%E5%BF%85%E8%A6%81%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%8F%8E%E9%9B%86%E5%99%A8%E3%82%92%E8%BF%BD%E5%8A%A0\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1) テーブル別の必要フィールド収集器を追加\u003c/h3\u003e\n\u003cp data-sourcepos=\"107:1-107:115\"\u003e新規ヘルパー（例: \u003ccode\u003ecollectRequiredFieldsForFullScan(stmt)\u003c/code\u003e）で、\u003ccode\u003ealias -\u0026gt; RequiredFieldSet\u003c/code\u003e を返す。\u003c/p\u003e\n\u003cp data-sourcepos=\"109:1-109:13\"\u003e収集対象:\u003c/p\u003e\n\u003cul data-sourcepos=\"110:1-117:0\"\u003e\n\u003cli data-sourcepos=\"110:1-110:51\"\u003eSELECT列（FIELD/AGGREGATE/ARITH/STRFUNC/CASE）\u003c/li\u003e\n\u003cli data-sourcepos=\"111:1-111:22\"\u003eJOIN ON 左右キー\u003c/li\u003e\n\u003cli data-sourcepos=\"112:1-112:7\"\u003eWHERE\u003c/li\u003e\n\u003cli data-sourcepos=\"113:1-113:10\"\u003eGROUP BY\u003c/li\u003e\n\u003cli data-sourcepos=\"114:1-114:8\"\u003eHAVING\u003c/li\u003e\n\u003cli data-sourcepos=\"115:1-115:10\"\u003eORDER BY\u003c/li\u003e\n\u003cli data-sourcepos=\"116:1-117:0\"\u003eDISTINCT評価で必要な列\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"118:1-118:10\"\u003eルール:\u003c/p\u003e\n\u003cul data-sourcepos=\"119:1-122:0\"\u003e\n\u003cli data-sourcepos=\"119:1-119:57\"\u003e\n\u003ccode\u003etableAlias\u003c/code\u003e 付き参照はそのテーブルへ加算\u003c/li\u003e\n\u003cli data-sourcepos=\"120:1-120:83\"\u003e非修飾参照は「主テーブル」へ加算（現行解決規則と整合）\u003c/li\u003e\n\u003cli data-sourcepos=\"121:1-122:0\"\u003e重複は Set で排除\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"123:1-123:61\"\u003e\n\u003cspan id=\"2-ワイルドカード時の安全フォールバック\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E3%83%AF%E3%82%A4%E3%83%AB%E3%83%89%E3%82%AB%E3%83%BC%E3%83%89%E6%99%82%E3%81%AE%E5%AE%89%E5%85%A8%E3%83%95%E3%82%A9%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2) ワイルドカード時の安全フォールバック\u003c/h3\u003e\n\u003cp data-sourcepos=\"124:1-124:82\"\u003e以下を含む場合は最小化を無効化（当該テーブルは全取得）:\u003c/p\u003e\n\u003cul data-sourcepos=\"125:1-128:0\"\u003e\n\u003cli data-sourcepos=\"125:1-125:12\"\u003e\u003ccode\u003eSELECT *\u003c/code\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"126:1-126:35\"\u003e\n\u003ccode\u003eSELECT a.*\u003c/code\u003e（将来対応時）\u003c/li\u003e\n\u003cli data-sourcepos=\"127:1-128:0\"\u003e\n\u003ccode\u003eSELECT _p.*\u003c/code\u003e（サブテーブル親ショートカット全取得）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"129:1-129:70\"\u003e\n\u003cspan id=\"3-サブテーブル仮想テーブルの必須列を強制追加\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E3%82%B5%E3%83%96%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E4%BB%AE%E6%83%B3%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E5%BF%85%E9%A0%88%E5%88%97%E3%82%92%E5%BC%B7%E5%88%B6%E8%BF%BD%E5%8A%A0\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3) サブテーブル仮想テーブルの必須列を強制追加\u003c/h3\u003e\n\u003cp data-sourcepos=\"130:1-130:86\"\u003e\u003ccode\u003eAPPxx$subtable\u003c/code\u003e を展開する場合、親取得時に最低限以下を含める。\u003c/p\u003e\n\u003cul data-sourcepos=\"131:1-134:0\"\u003e\n\u003cli data-sourcepos=\"131:1-131:35\"\u003e\n\u003ccode\u003e$id\u003c/code\u003e（\u003ccode\u003e_pid\u003c/code\u003e 生成に必須）\u003c/li\u003e\n\u003cli data-sourcepos=\"132:1-132:47\"\u003e\n\u003ccode\u003esubtableCode\u003c/code\u003e 本体（行展開に必須）\u003c/li\u003e\n\u003cli data-sourcepos=\"133:1-134:0\"\u003e\n\u003ccode\u003e_p.xxx\u003c/code\u003e 参照に必要な親列（\u003ccode\u003exxx\u003c/code\u003e）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"135:1-135:7\"\u003e補足:\u003c/p\u003e\n\u003cul data-sourcepos=\"136:1-137:0\"\u003e\n\u003cli data-sourcepos=\"136:1-137:0\"\u003e\n\u003ccode\u003efetchAll()\u003c/code\u003e は fields指定時に \u003ccode\u003e$id\u003c/code\u003e を自動追加するが、要件明示のため設計上も必須扱いにする。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"138:1-138:48\"\u003e\n\u003cspan id=\"4-サブクエリ--with-への適用単位\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-%E3%82%B5%E3%83%96%E3%82%AF%E3%82%A8%E3%83%AA--with-%E3%81%B8%E3%81%AE%E9%81%A9%E7%94%A8%E5%8D%98%E4%BD%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4) サブクエリ / WITH への適用単位\u003c/h3\u003e\n\u003cul data-sourcepos=\"139:1-142:0\"\u003e\n\u003cli data-sourcepos=\"139:1-139:62\"\u003eサブクエリは「独立SELECT」として個別に収集\u003c/li\u003e\n\u003cli data-sourcepos=\"140:1-140:33\"\u003eWITHは各SELECT単位で収集\u003c/li\u003e\n\u003cli data-sourcepos=\"141:1-142:0\"\u003eCTEインライン化後はインライン後SELECTに対して通常収集\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"143:1-143:21\"\u003e\n\u003cspan id=\"実装ステップ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E3%82%B9%E3%83%86%E3%83%83%E3%83%97\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e実装ステップ\u003c/h2\u003e\n\u003col data-sourcepos=\"145:1-145:27\"\u003e\n\u003cli data-sourcepos=\"145:1-145:27\"\u003e収集ロジック追加\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"146:1-148:0\"\u003e\n\u003cli data-sourcepos=\"146:1-146:96\"\u003e追加先候補: \u003ccode\u003esrc/converter/selectToKintone.ts\u003c/code\u003e または \u003ccode\u003esrc/engine/\u003c/code\u003e 新規ファイル\u003c/li\u003e\n\u003cli data-sourcepos=\"147:1-148:0\"\u003eAST走査ユーティリティを実装（WhereExpr, ArithNode, StringFuncExpr, AggOperand, CaseWhen）\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"149:1-149:45\"\u003e\n\u003cli data-sourcepos=\"149:1-149:45\"\u003eFULL_SCAN取得呼び出しの差し替え\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"150:1-152:0\"\u003e\n\u003cli data-sourcepos=\"150:1-150:63\"\u003e\n\u003ccode\u003efetchTableRecordsForFullScan()\u003c/code\u003e に \u003ccode\u003efields\u003c/code\u003e 引数を渡す\u003c/li\u003e\n\u003cli data-sourcepos=\"151:1-152:0\"\u003e\n\u003ccode\u003emain/join/subtable\u003c/code\u003e それぞれテーブル別フィールドを適用\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"153:1-153:16\"\u003e\n\u003cli data-sourcepos=\"153:1-153:16\"\u003eEXPLAIN更新\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"154:1-156:0\"\u003e\n\u003cli data-sourcepos=\"154:1-154:106\"\u003eFULL_SCAN時の \u003ccode\u003efields:\u003c/code\u003e を \u003ccode\u003e(全フィールド)\u003c/code\u003e 固定から、実際の収集結果表示へ変更\u003c/li\u003e\n\u003cli data-sourcepos=\"155:1-156:0\"\u003eJOIN先も同様に表示\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"157:1-157:18\"\u003e\n\u003cli data-sourcepos=\"157:1-157:18\"\u003eテスト追加\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"158:1-161:0\"\u003e\n\u003cli data-sourcepos=\"158:1-158:32\"\u003e既存互換（結果一致）\u003c/li\u003e\n\u003cli data-sourcepos=\"159:1-159:41\"\u003eフィールド収集の単体ケース\u003c/li\u003e\n\u003cli data-sourcepos=\"160:1-161:0\"\u003eEXPLAIN出力の期待値更新\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"162:1-162:15\"\u003e\n\u003cspan id=\"影響範囲\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%BD%B1%E9%9F%BF%E7%AF%84%E5%9B%B2\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e影響範囲\u003c/h2\u003e\n\u003cul data-sourcepos=\"163:1-168:0\"\u003e\n\u003cli data-sourcepos=\"163:1-163:18\"\u003e\u003ccode\u003esrc/execute.ts\u003c/code\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"164:1-164:78\"\u003e\n\u003ccode\u003esrc/converter/selectToKintone.ts\u003c/code\u003e（または新規収集モジュール）\u003c/li\u003e\n\u003cli data-sourcepos=\"165:1-165:33\"\u003e\u003ccode\u003esrc/__tests__/execute.test.ts\u003c/code\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"166:1-166:33\"\u003e\u003ccode\u003esrc/__tests__/explain.test.ts\u003c/code\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"167:1-168:0\"\u003e必要なら \u003ccode\u003edocs/explain_spec.md\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"169:1-169:30\"\u003e\n\u003cspan id=\"互換性リスクと対策\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BA%92%E6%8F%9B%E6%80%A7%E3%83%AA%E3%82%B9%E3%82%AF%E3%81%A8%E5%AF%BE%E7%AD%96\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e互換性リスクと対策\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"171:1-171:55\"\u003e\n\u003cspan id=\"リスク1-参照列取り漏れで結果不整合\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%AA%E3%82%B9%E3%82%AF1-%E5%8F%82%E7%85%A7%E5%88%97%E5%8F%96%E3%82%8A%E6%BC%8F%E3%82%8C%E3%81%A7%E7%B5%90%E6%9E%9C%E4%B8%8D%E6%95%B4%E5%90%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eリスク1: 参照列取り漏れで結果不整合\u003c/h3\u003e\n\u003cp data-sourcepos=\"172:1-172:7\"\u003e対策:\u003c/p\u003e\n\u003cul data-sourcepos=\"173:1-175:0\"\u003e\n\u003cli data-sourcepos=\"173:1-173:81\"\u003e走査対象を \u003ccode\u003eSELECT/JOIN/WHERE/GROUP BY/HAVING/ORDER BY/DISTINCT\u003c/code\u003e 全網羅\u003c/li\u003e\n\u003cli data-sourcepos=\"174:1-175:0\"\u003eワイルドカード時は全取得フォールバック\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"176:1-176:46\"\u003e\n\u003cspan id=\"リスク2-サブテーブル展開壊れ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%AA%E3%82%B9%E3%82%AF2-%E3%82%B5%E3%83%96%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E5%B1%95%E9%96%8B%E5%A3%8A%E3%82%8C\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eリスク2: サブテーブル展開壊れ\u003c/h3\u003e\n\u003cp data-sourcepos=\"177:1-177:7\"\u003e対策:\u003c/p\u003e\n\u003cul data-sourcepos=\"178:1-180:0\"\u003e\n\u003cli data-sourcepos=\"178:1-178:37\"\u003e\n\u003ccode\u003e$id\u003c/code\u003e + \u003ccode\u003esubtableCode\u003c/code\u003e を必須化\u003c/li\u003e\n\u003cli data-sourcepos=\"179:1-180:0\"\u003e\n\u003ccode\u003e_p.xxx\u003c/code\u003e の親列加算をテストで固定\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"181:1-181:50\"\u003e\n\u003cspan id=\"リスク3-explain表示と実挙動の乖離\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%AA%E3%82%B9%E3%82%AF3-explain%E8%A1%A8%E7%A4%BA%E3%81%A8%E5%AE%9F%E6%8C%99%E5%8B%95%E3%81%AE%E4%B9%96%E9%9B%A2\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eリスク3: EXPLAIN表示と実挙動の乖離\u003c/h3\u003e\n\u003cp data-sourcepos=\"182:1-182:7\"\u003e対策:\u003c/p\u003e\n\u003cul data-sourcepos=\"183:1-184:0\"\u003e\n\u003cli data-sourcepos=\"183:1-184:0\"\u003e実行時と同じ収集関数をEXPLAINでも再利用\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"185:1-185:18\"\u003e\n\u003cspan id=\"テスト観点\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%86%E3%82%B9%E3%83%88%E8%A6%B3%E7%82%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eテスト観点\u003c/h2\u003e\n\u003col data-sourcepos=\"187:1-187:27\"\u003e\n\u003cli data-sourcepos=\"187:1-187:27\"\u003eJOIN + GROUP BY + 集計\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"188:1-190:0\"\u003e\n\u003cli data-sourcepos=\"188:1-188:38\"\u003e取得fieldsが最小集合になる\u003c/li\u003e\n\u003cli data-sourcepos=\"189:1-190:0\"\u003e実行結果が変更前と一致\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"191:1-191:33\"\u003e\n\u003cli data-sourcepos=\"191:1-191:33\"\u003eWHERE/HAVING/ORDER BY参照列\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"192:1-193:0\"\u003e\n\u003cli data-sourcepos=\"192:1-193:0\"\u003e対象列がfieldsに含まれる\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"194:1-194:21\"\u003e\n\u003cli data-sourcepos=\"194:1-194:21\"\u003eサブテーブル\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"195:1-198:0\"\u003e\n\u003cli data-sourcepos=\"195:1-195:47\"\u003e\n\u003ccode\u003e$id\u003c/code\u003e / subtableCode 取得が保証される\u003c/li\u003e\n\u003cli data-sourcepos=\"196:1-196:32\"\u003e\n\u003ccode\u003e_p.xxx\u003c/code\u003e 参照が壊れない\u003c/li\u003e\n\u003cli data-sourcepos=\"197:1-198:0\"\u003e\n\u003ccode\u003e_p.*\u003c/code\u003e で全取得フォールバック\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"199:1-199:18\"\u003e\n\u003cli data-sourcepos=\"199:1-199:18\"\u003eサブクエリ\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"200:1-201:0\"\u003e\n\u003cli data-sourcepos=\"200:1-201:0\"\u003e外側と内側で独立して必要列収集\u003c/li\u003e\n\u003c/ul\u003e\n\u003col data-sourcepos=\"202:1-202:7\"\u003e\n\u003cli data-sourcepos=\"202:1-202:7\"\u003eWITH\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul data-sourcepos=\"203:1-204:0\"\u003e\n\u003cli data-sourcepos=\"203:1-204:0\"\u003eCTE本体・mainの各SELECTで必要列収集\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"205:1-205:24\"\u003e\n\u003cspan id=\"段階リリース案\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%AE%B5%E9%9A%8E%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E6%A1%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e段階リリース案\u003c/h2\u003e\n\u003cul data-sourcepos=\"206:1-209:0\"\u003e\n\u003cli data-sourcepos=\"206:1-206:64\"\u003ePhase 1: 通常テーブル（JOIN/GROUP BY/HAVING/ORDER BY）\u003c/li\u003e\n\u003cli data-sourcepos=\"207:1-207:76\"\u003ePhase 2: サブテーブル専用要件（\u003ccode\u003e$id\u003c/code\u003e / \u003ccode\u003e_p\u003c/code\u003e / \u003ccode\u003esubtableCode\u003c/code\u003e）\u003c/li\u003e\n\u003cli data-sourcepos=\"208:1-209:0\"\u003ePhase 3: EXPLAIN整合 + ドキュメント更新\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"210:1-210:15\"\u003e\n\u003cspan id=\"成功条件\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%88%90%E5%8A%9F%E6%9D%A1%E4%BB%B6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e成功条件\u003c/h2\u003e\n\u003cul data-sourcepos=\"211:1-215:0\"\u003e\n\u003cli data-sourcepos=\"211:1-211:60\"\u003eFULL_SCAN時の \u003ccode\u003efields\u003c/code\u003e が全取得固定でなくなる\u003c/li\u003e\n\u003cli data-sourcepos=\"212:1-212:41\"\u003e代表クエリで結果互換を維持\u003c/li\u003e\n\u003cli data-sourcepos=\"213:1-213:45\"\u003eEXPLAINに実取得fieldsが表示される\u003c/li\u003e\n\u003cli data-sourcepos=\"214:1-215:0\"\u003e既存テスト + 追加テストがすべて通過\u003c/li\u003e\n\u003c/ul\u003e\n","body":"[kintone でSQL実行しよう その８（しくみ解説）](https://qiita.com/rex0220/items/438587c27dc51d109415)の続きです。\n\n# 概要\n\n[rex0220 kSQL 顧客ランク別集計](https://qiita.com/rex0220/items/bfb0149b57c5da9b4a2f)の EXPAIN（実行計画）をみたら、全項目取得となっていたので必要な項目のみ取得するように改善してみました。\n\n\n- 変更前：全フィールド取得\n\n![2026-04-06_11h48_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/15c31b0c-b1bb-416b-8212-ef43d01e3d96.png)\n\n- 変更後：SQLで利用するフィールド取得\n\n![2026-04-06_12h07_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/9e9cc866-1cb0-474c-9c8c-17a8b650c1f9.png)\n\n# REST API の結果\n\nブラウザーの Network で REST API の結果をみると、確かに必要フィールドのみ取得しています。\n\n- 顧客管理アプリ\n\n![2026-04-06_12h07_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/902188fa-dc93-4459-b6dd-23299f30dbe3.png)\n\n- 案件管理アプリ\n\n![2026-04-06_12h06_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c6b2abc7-9f1e-465c-aaf1-3244022e9675.png)\n\n# FULL_SCAN時の必要フィールド取得最適化 実装案\n\nCodex の実装案です。\n何回かやり取りをして、実装案をまとめてもらいました。\n\n```\n下記のSQL で、全フィールド取得している\nパフォーマス改善のため、必要な項目のみ取得するようにできるか、検討して\n\nSELECT a.顧客ランク AS 顧客ランク, FORMAT(SUM(b.合計費用),'#,##0') AS 合計\nFROM APP89 AS a\nINNER JOIN APP88 AS b ON a.顧客名 = b.顧客名\nGROUP BY a.顧客ランク\n\n\n1\tmode: FULL_SCAN\n2\treason: JOIN あり, GROUP BY あり\n3\tapp: APP89 AS a (89)\n4\tkintone query: (全件取得)\n5\tfields: (全フィールド)\n6\tJOIN: APP88 AS b (88)\n7\tkintone query: (全件取得)\n8\tfields: (全フィールド)\n```\n```\nサブテーブルを SELECT する場合は、$id なども必要になるが、影響は？\n```\n```\nWIDTH の場合は？\n```\n```\nサブクエリーは？\n```\n```\n実装案をマークダウンファイルに作成\n```\n...\n\n## 背景\n現状の `FULL_SCAN` では `fetchAll(..., fields: [])` を使用しており、常に全フィールド取得になる。\nJOIN / GROUP BY / HAVING / DISTINCT / ORDER BY を含むクエリでは全件取得が必要なケースが多いが、全フィールド取得は不要な通信量・メモリ使用・JS処理コストを増やす。\n\n対象例:\n\n```sql\nSELECT a.顧客ランク AS 顧客ランク, FORMAT(SUM(b.合計費用),'#,##0') AS 合計\nFROM APP89 AS a\nINNER JOIN APP88 AS b ON a.顧客名 = b.顧客名\nGROUP BY a.顧客ランク\n```\n\nこの場合の必要フィールドは以下で十分。\n- APP89(a): `顧客名`, `顧客ランク`\n- APP88(b): `顧客名`, `合計費用`\n\n## 目的\n- FULL_SCAN時の取得フィールドを「クエリ実行に必要な最小集合」にする\n- 結果互換性（既存SQLの実行結果）を維持する\n- EXPLAIN表示を実取得フィールドと整合させる\n\n## 非目的\n- FULL_SCAN自体をSIMPLE化する最適化（JOIN/GROUP BYの実行方式変更）\n- 相関サブクエリ対応の追加（現行仕様外）\n\n## 期待効果\n- レコード1件あたりのペイロード削減\n- JSONパース、flatten、JOIN時のオブジェクト結合コスト削減\n- メモリ使用量削減\n\n注: 取得件数は変わらないため、APIページ数（呼び出し回数）は基本不変。\n\n## 現状実装のボトルネック\n- `src/execute.ts` の `fetchTableRecordsForFullScan()` で `fields: []` 固定\n- `src/converter/selectToKintone.ts` の `selectToFetchAllParams()` が `fields: []` を返す\n- `EXPLAIN` の FULL_SCAN表示が常に `(全フィールド)`\n\n## 提案アーキテクチャ\n\n### 1) テーブル別の必要フィールド収集器を追加\n新規ヘルパー（例: `collectRequiredFieldsForFullScan(stmt)`）で、`alias -\u003e RequiredFieldSet` を返す。\n\n収集対象:\n- SELECT列（FIELD/AGGREGATE/ARITH/STRFUNC/CASE）\n- JOIN ON 左右キー\n- WHERE\n- GROUP BY\n- HAVING\n- ORDER BY\n- DISTINCT評価で必要な列\n\nルール:\n- `tableAlias` 付き参照はそのテーブルへ加算\n- 非修飾参照は「主テーブル」へ加算（現行解決規則と整合）\n- 重複は Set で排除\n\n### 2) ワイルドカード時の安全フォールバック\n以下を含む場合は最小化を無効化（当該テーブルは全取得）:\n- `SELECT *`\n- `SELECT a.*`（将来対応時）\n- `SELECT _p.*`（サブテーブル親ショートカット全取得）\n\n### 3) サブテーブル仮想テーブルの必須列を強制追加\n`APPxx$subtable` を展開する場合、親取得時に最低限以下を含める。\n- `$id`（`_pid` 生成に必須）\n- `subtableCode` 本体（行展開に必須）\n- `_p.xxx` 参照に必要な親列（`xxx`）\n\n補足:\n- `fetchAll()` は fields指定時に `$id` を自動追加するが、要件明示のため設計上も必須扱いにする。\n\n### 4) サブクエリ / WITH への適用単位\n- サブクエリは「独立SELECT」として個別に収集\n- WITHは各SELECT単位で収集\n- CTEインライン化後はインライン後SELECTに対して通常収集\n\n## 実装ステップ\n\n1. 収集ロジック追加\n- 追加先候補: `src/converter/selectToKintone.ts` または `src/engine/` 新規ファイル\n- AST走査ユーティリティを実装（WhereExpr, ArithNode, StringFuncExpr, AggOperand, CaseWhen）\n\n2. FULL_SCAN取得呼び出しの差し替え\n- `fetchTableRecordsForFullScan()` に `fields` 引数を渡す\n- `main/join/subtable` それぞれテーブル別フィールドを適用\n\n3. EXPLAIN更新\n- FULL_SCAN時の `fields:` を `(全フィールド)` 固定から、実際の収集結果表示へ変更\n- JOIN先も同様に表示\n\n4. テスト追加\n- 既存互換（結果一致）\n- フィールド収集の単体ケース\n- EXPLAIN出力の期待値更新\n\n## 影響範囲\n- `src/execute.ts`\n- `src/converter/selectToKintone.ts`（または新規収集モジュール）\n- `src/__tests__/execute.test.ts`\n- `src/__tests__/explain.test.ts`\n- 必要なら `docs/explain_spec.md`\n\n## 互換性リスクと対策\n\n### リスク1: 参照列取り漏れで結果不整合\n対策:\n- 走査対象を `SELECT/JOIN/WHERE/GROUP BY/HAVING/ORDER BY/DISTINCT` 全網羅\n- ワイルドカード時は全取得フォールバック\n\n### リスク2: サブテーブル展開壊れ\n対策:\n- `$id` + `subtableCode` を必須化\n- `_p.xxx` の親列加算をテストで固定\n\n### リスク3: EXPLAIN表示と実挙動の乖離\n対策:\n- 実行時と同じ収集関数をEXPLAINでも再利用\n\n## テスト観点\n\n1. JOIN + GROUP BY + 集計\n- 取得fieldsが最小集合になる\n- 実行結果が変更前と一致\n\n2. WHERE/HAVING/ORDER BY参照列\n- 対象列がfieldsに含まれる\n\n3. サブテーブル\n- `$id` / subtableCode 取得が保証される\n- `_p.xxx` 参照が壊れない\n- `_p.*` で全取得フォールバック\n\n4. サブクエリ\n- 外側と内側で独立して必要列収集\n\n5. WITH\n- CTE本体・mainの各SELECTで必要列収集\n\n## 段階リリース案\n- Phase 1: 通常テーブル（JOIN/GROUP BY/HAVING/ORDER BY）\n- Phase 2: サブテーブル専用要件（`$id` / `_p` / `subtableCode`）\n- Phase 3: EXPLAIN整合 + ドキュメント更新\n\n## 成功条件\n- FULL_SCAN時の `fields` が全取得固定でなくなる\n- 代表クエリで結果互換を維持\n- EXPLAINに実取得fieldsが表示される\n- 既存テスト + 追加テストがすべて通過\n\n","coediting":false,"comments_count":0,"created_at":"2026-04-06T15:05:58+09:00","group":null,"id":"c88067818cf41424615f","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"SQL","versions":[]},{"name":"kintone","versions":[]},{"name":"codex","versions":[]}],"title":"kintone でSQL実行しよう その９（パフォーマンス改善）","updated_at":"2026-04-06T15:05:58+09:00","url":"https://qiita.com/rex0220/items/c88067818cf41424615f","user":{"description":"","facebook_id":"","followees_count":0,"followers_count":150,"github_login_name":"rex0220","id":"rex0220","items_count":594,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":100572,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/100572/profile-images/1473708137","team_only":false,"twitter_screen_name":"rex02201","website_url":"https://rex0220.stores.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:153\"\u003e2026年2月21日、kintone Café 和歌山とSORACOM UGの共催で、SORACOM GPSマルチユニットを使ったハンズオンを開催しました。\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-3:124\"\u003e「SORACOM GPS マルチユニット のデータを kintone に保存する」、元祖の解説記事はこちらです。\u003c/p\u003e\n\u003cp data-sourcepos=\"5:1-5:54\"\u003e\u003ciframe id=\"qiita-embed-content__ac81e503f1cda1dcebbbe60370f7b763\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__ac81e503f1cda1dcebbbe60370f7b763\" data-content=\"https%3A%2F%2Fqiita.com%2Fyukataoka%2Fitems%2Fc07b78f5151c29ac8858\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\"\u003e\n\u003c/iframe\u003e\n\u003c/p\u003e\n\u003cp data-sourcepos=\"7:1-7:314\"\u003eノーコードではなく、AWS Lambdaを使ってkintoneにデータを登録する解説記事です。※GPSマルチユニットの設定が詳細に説明されていますので、私の記事で紹介できていないGPSマルチユニットについての設定の確認をするのにお勧めです。\u003c/p\u003e\n\u003cp data-sourcepos=\"9:1-9:290\"\u003eAWS Lambdaを利用した内容の記事とは異なり、ハンズオンでは、ノーコードでいろいろなシステムを連携するiPaaSの一つ「Yoom」を利用して、もっと気軽にノーコードでkintoneへのデータ登録ができる内容になっています。\u003c/p\u003e\n\u003cp data-sourcepos=\"11:1-11:56\"\u003e\u003ciframe id=\"qiita-embed-content__7a882579a5e320f974183fbd65f3059f\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__7a882579a5e320f974183fbd65f3059f\" data-content=\"https%3A%2F%2Fkintone-cafe-wakayama.connpass.com%2Fevent%2F376877%2F\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\"\u003e\n\u003c/iframe\u003e\n\u003c/p\u003e\n\u003cp data-sourcepos=\"13:1-13:47\"\u003e\u003ciframe id=\"qiita-embed-content__540d286df925b8875c0fb4de13d671e1\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__540d286df925b8875c0fb4de13d671e1\" data-content=\"https%3A%2F%2Fnote.com%2Fopen_squid1443%2Fn%2Fnfc68d83b0ad5\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\"\u003e\n\u003c/iframe\u003e\n\u003c/p\u003e\n\u003cp data-sourcepos=\"15:1-16:220\"\u003e当日はGPSマルチユニットの貸し出しがあって、手ぶらで体験できる（言い過ぎでした、パソコンは持参必要です）のですが、自分で移動の履歴がとりたくなってきたので、自分でもGPSマルチユニットを買いました。\u003cbr\u003e\n設定は、当日と同じSORACOM→Yoom→kintoneではなく、運営のメンバーのチャットで見かけた「Fluxでできる」という会話をヒントにやってみたものをメモしておきます。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"20:1-20:27\"\u003e\n\u003cspan id=\"kintoneアプリの準備\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E6%BA%96%E5%82%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintoneアプリの準備\u003c/h1\u003e\n\u003cp data-sourcepos=\"21:1-22:56\"\u003eあらかじめ、GPSユニットが自動でデータを入れてくれる箱を用意しておきます。\u003cbr\u003e\n最低限、これだけ設定しておけばOKです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"24:1-24:45\"\u003e\n\u003cspan id=\"フィールドフィールドコード\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%B3%E3%83%BC%E3%83%89\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eフィールド：フィールドコード\u003c/h2\u003e\n\u003cp data-sourcepos=\"25:1-26:227\"\u003e4つ。数値フィールドです。\u003cbr\u003e\nkintoneのフィールドコードは任意に設定できますが、管理を分かりやすくするため、SORACOM Fluxで受信するJSONデータのキー名（プロパティ名）に合わせて設定しています。\u003c/p\u003e\n\u003cul data-sourcepos=\"27:1-31:0\"\u003e\n\u003cli data-sourcepos=\"27:1-27:14\"\u003e緯度：lat\u003c/li\u003e\n\u003cli data-sourcepos=\"28:1-28:14\"\u003e経度：lon\u003c/li\u003e\n\u003cli data-sourcepos=\"29:1-29:15\"\u003e温度：temp\u003c/li\u003e\n\u003cli data-sourcepos=\"30:1-31:0\"\u003e湿度：humi\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"32:1-33:179\"\u003e参考\u003cbr\u003e\nHome \u0026gt; スタートガイド \u0026gt; IoT デバイス \u0026gt; GPS マルチユニット SORACOM Edition ユーザーガイド \u0026gt; リファレンス \u0026gt; 送信されるデータフォーマット\u003c/p\u003e\n\u003cp data-sourcepos=\"35:1-35:71\"\u003e\u003ciframe id=\"qiita-embed-content__a3465796894fa063848f11239835ec92\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__a3465796894fa063848f11239835ec92\" data-content=\"https%3A%2F%2Fusers.soracom.io%2Fja-jp%2Fguides%2Fiot-devices%2Fgps-multiunit%2Fformat%2F\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\"\u003e\n\u003c/iframe\u003e\n\u003c/p\u003e\n\u003ch2 data-sourcepos=\"37:1-37:18\"\u003e\n\u003cspan id=\"apiトークン\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#api%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eAPIトークン\u003c/h2\u003e\n\u003cp data-sourcepos=\"38:1-38:102\"\u003eGPSマルチユニットからのデータを外部から登録するために、後で使います。\u003c/p\u003e\n\u003cul data-sourcepos=\"39:1-40:0\"\u003e\n\u003cli data-sourcepos=\"39:1-40:0\"\u003e「レコード追加」の権限\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"41:1-41:18\"\u003e\n\u003cspan id=\"高度な設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E9%AB%98%E5%BA%A6%E3%81%AA%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e高度な設定\u003c/h2\u003e\n\u003cp data-sourcepos=\"42:1-42:244\"\u003e緯度経度が小数点以下の値の桁数が多いので、これを設定しておかないと、デフォルトの4桁より小さい数値がなくなってしまい、詳細な位置情報が取得できなくなってしまいます。\u003c/p\u003e\n\u003cul data-sourcepos=\"43:1-44:0\"\u003e\n\u003cli data-sourcepos=\"43:1-44:0\"\u003e小数部の桁数：8\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 data-sourcepos=\"45:1-45:43\"\u003e\n\u003cspan id=\"soracom-gpsマルチユニットの設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#soracom-gps%E3%83%9E%E3%83%AB%E3%83%81%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88%E3%81%AE%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eSORACOM GPSマルチユニットの設定\u003c/h1\u003e\n\u003cp data-sourcepos=\"46:1-48:135\"\u003eここ、設定画面での設定と、GPSマルチユニットへの反映部分、再起動をしたりして何とかなっていますが、自分ではどうもうまく整理できていないので、省略します。\u003cbr\u003e\nたぶん、電源を入れたときに窓際にいると、悩むことは少ないような気がします。\u003cbr\u003e\n設定中に、どこにあるか自分がよく迷ったところがわかってきたので、それだけまとめておきます。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"50:1-50:54\"\u003e\n\u003cspan id=\"私が設定中によく迷子になったところ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%A7%81%E3%81%8C%E8%A8%AD%E5%AE%9A%E4%B8%AD%E3%81%AB%E3%82%88%E3%81%8F%E8%BF%B7%E5%AD%90%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%93%E3%82%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e私が設定中によく迷子になったところ\u003c/h2\u003e\n\u003cp data-sourcepos=\"51:1-51:180\"\u003eSIM単体の設定、SIMグループでの設定、デバイスごと（今回ならGPSマルチユニット）の設定があることがわかれば難しくないのかも…？\u003c/p\u003e\n\u003ch3 data-sourcepos=\"53:1-53:87\"\u003e\n\u003cspan id=\"gpsマルチユニットからのデータを見る画面soracom-harvest-data\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#gps%E3%83%9E%E3%83%AB%E3%83%81%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88%E3%81%8B%E3%82%89%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E8%A6%8B%E3%82%8B%E7%94%BB%E9%9D%A2soracom-harvest-data\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eGPSマルチユニットからのデータを見る画面（SORACOM Harvest Data）\u003c/h3\u003e\n\u003cp data-sourcepos=\"54:1-54:35\"\u003eいずれの操作でもOKです。\u003c/p\u003e\n\u003cul data-sourcepos=\"55:3-58:92\"\u003e\n\u003cli data-sourcepos=\"55:3-56:41\"\u003e☰メニュー \u0026gt; データ収集・累積・可視化 \u0026gt; SORACOM Harvest \u0026gt; Harvest データ　\u003cbr\u003e\n⇒「リソース▼」でSIMを選択\u003c/li\u003e\n\u003cli data-sourcepos=\"57:3-58:92\"\u003e☰メニュー \u0026gt; SORACOM Air for セルラー \u0026gt; SIM管理\u003cbr\u003e\n⇒SIMを✅選択して、「操作▼」から「Harvest Dataを表示」をクリック\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"59:1-59:94\"\u003e\n\u003cspan id=\"定期送信のオンオフや頻度を変えたいgpsマルチユニットの設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AE%9A%E6%9C%9F%E9%80%81%E4%BF%A1%E3%81%AE%E3%82%AA%E3%83%B3%E3%82%AA%E3%83%95%E3%82%84%E9%A0%BB%E5%BA%A6%E3%82%92%E5%A4%89%E3%81%88%E3%81%9F%E3%81%84gps%E3%83%9E%E3%83%AB%E3%83%81%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88%E3%81%AE%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e定期送信のオンオフや頻度を変えたい（GPSマルチユニットの設定）\u003c/h3\u003e\n\u003cul data-sourcepos=\"60:3-60:97\"\u003e\n\u003cli data-sourcepos=\"60:3-60:97\"\u003e☰メニュー \u0026gt; ガジェット管理 \u0026gt; GPSマルチユニット \u0026gt; デバイス設定変更\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"61:1-61:77\"\u003e\n\u003cspan id=\"バイナリパーサーの設定soracom-air-for-セルラー設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%83%91%E3%83%BC%E3%82%B5%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9Asoracom-air-for-%E3%82%BB%E3%83%AB%E3%83%A9%E3%83%BC%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eバイナリパーサーの設定（SORACOM Air for セルラー設定）\u003c/h3\u003e\n\u003cul data-sourcepos=\"62:3-63:111\"\u003e\n\u003cli data-sourcepos=\"62:3-63:111\"\u003e☰メニュー \u0026gt; SORACOM Air for セルラー \u0026gt; SIMグループ　\u003cbr\u003e\n⇒グループを選択して、右がわ上の方で「SORACOM Air for セルラー設定」をクリック\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"64:1-64:61\"\u003e\n\u003cspan id=\"他サービスへの送信先の設定soracom-beam\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BB%96%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%B8%E3%81%AE%E9%80%81%E4%BF%A1%E5%85%88%E3%81%AE%E8%A8%AD%E5%AE%9Asoracom-beam\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e他サービスへの送信先の設定（SORACOM Beam）\u003c/h3\u003e\n\u003cp data-sourcepos=\"65:1-65:36\"\u003e※SORACOM Fluxの時は使わない\u003c/p\u003e\n\u003cul data-sourcepos=\"66:3-68:0\"\u003e\n\u003cli data-sourcepos=\"66:3-68:0\"\u003e\n\u003cdel\u003e☰メニュー \u0026gt; SORACOM Air for セルラー \u0026gt; SIMグループ\u003c/del\u003e\u003cbr\u003e\n\u003cdel\u003e⇒グループを選択して、右がわ下の方で「SORACOM Beam」をクリック\u003c/del\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"69:1-69:107\"\u003eHarvest データで、データが取得できていることが確認できたら、次に進みます。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"71:1-71:23\"\u003e\n\u003cspan id=\"soracom-fluxの設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#soracom-flux%E3%81%AE%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eSORACOM Fluxの設定\u003c/h1\u003e\n\u003cp data-sourcepos=\"72:1-72:94\"\u003eGPSマルチユニットのデータをkintoneに送る設定（アプリ）を作ります。\u003c/p\u003e\n\u003cul data-sourcepos=\"74:1-94:0\"\u003e\n\u003cli data-sourcepos=\"74:1-75:51\"\u003e\n\u003cp data-sourcepos=\"74:3-74:41\"\u003eSORACOM Fluxの設定画面を開く。\u003c/p\u003e\n\u003cul data-sourcepos=\"75:3-75:51\"\u003e\n\u003cli data-sourcepos=\"75:3-75:51\"\u003e☰メニュー \u0026gt; SORACOM Flux \u0026gt; Flux アプリ\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"76:1-76:66\"\u003e\n\u003cp data-sourcepos=\"76:3-76:66\"\u003e「新しいFluxアプリを作成する」をクリックする\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"77:1-77:68\"\u003e\n\u003cp data-sourcepos=\"77:3-77:68\"\u003e「最初から作成」をクリックし、名前を付ける。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"78:1-78:113\"\u003e\n\u003cp data-sourcepos=\"78:3-78:113\"\u003e名前を付けたアプリの画面になるので、「チャネルを作成する」をクリックする。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"79:1-81:0\"\u003e\n\u003cp data-sourcepos=\"79:3-80:161\"\u003e「新しいチャネルを作成」で「IoTデバイス」を選択する。\u003cbr\u003e\n\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F7c0a1598-3b17-49ac-89c3-34c30956fd34.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=be0770ef9712f92448168507299226f4\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F7c0a1598-3b17-49ac-89c3-34c30956fd34.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=be0770ef9712f92448168507299226f4\" alt=\"スクリーンショット 2026-04-06 112346.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F7c0a1598-3b17-49ac-89c3-34c30956fd34.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=14ad4b98f55b69d5d762cd9e3bb988c2 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/7c0a1598-3b17-49ac-89c3-34c30956fd34.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"82:1-82:80\"\u003e\n\u003cp data-sourcepos=\"82:3-82:80\"\u003e名前はそのままか適当に編集し、SIMグループを選択する。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"83:1-94:0\"\u003e\n\u003cp data-sourcepos=\"83:3-83:18\"\u003eWebhookの詳細\u003c/p\u003e\n\u003cul data-sourcepos=\"84:3-94:0\"\u003e\n\u003cli data-sourcepos=\"84:3-84:27\"\u003eHTTPメソッド：POST\u003c/li\u003e\n\u003cli data-sourcepos=\"85:3-85:70\"\u003eURL：https://（サブドメイン）.cybozu.com/k/v1/record.json\u003c/li\u003e\n\u003cli data-sourcepos=\"86:3-94:0\"\u003eHTTPヘッダー：\n\u003cul data-sourcepos=\"87:5-94:0\"\u003e\n\u003cli data-sourcepos=\"87:5-87:73\"\u003eX-Cybozu-API-Token：先ほどkintoneで用意したAPIトークン\u003c/li\u003e\n\u003cli data-sourcepos=\"88:5-88:37\"\u003econtent-type：application/json\u003c/li\u003e\n\u003cli data-sourcepos=\"89:5-94:0\"\u003eHTTPボディ\u003cbr\u003e\n\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F1370b5c7-5da4-47da-845c-ca852d089e89.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=f6abb79682072cd3758db1a6b3e1a86d\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F1370b5c7-5da4-47da-845c-ca852d089e89.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=f6abb79682072cd3758db1a6b3e1a86d\" alt=\"スクリーンショット 2026-04-06 114924.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F1370b5c7-5da4-47da-845c-ca852d089e89.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=e344fe8c1ccb5b6dff8fce5ee798545a 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/1370b5c7-5da4-47da-845c-ca852d089e89.png\" loading=\"lazy\"\u003e\u003c/a\u003e\n\u003cul data-sourcepos=\"91:7-94:0\"\u003e\n\u003cli data-sourcepos=\"91:7-91:39\"\u003e「application/json」を選択\u003c/li\u003e\n\u003cli data-sourcepos=\"92:7-94:0\"\u003e中味は下記\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"text\" data-sourcepos=\"95:1-105:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e{\n  \"app\": アプリID,\n  \"record\": {\n    \"temp\": { \"value\": ${payload.temp} },\n    \"humi\": { \"value\": ${payload.humi} },\n    \"lat\": { \"value\": ${payload.lat} },\n    \"lon\": { \"value\": ${payload.lon} }\n  }\n}\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"108:1-108:76\"\u003eこれで保存したら、kintoneへの登録が始まっていました。\u003c/p\u003e\n\u003cp data-sourcepos=\"110:1-110:321\"\u003eリクエストの中身をポチポチ選択して作ることができないので、ノーコードとは言えないかもしれないけれど、SORACOM→Yoom→kintoneの設定のときよりも、別サービスとの間で行ったり来たりするのが少ないので、わかりやすいと感じました。\u003c/p\u003e\n\u003cp data-sourcepos=\"112:1-112:127\"\u003eここまでで、kintoneに移動履歴がどんどんたまっていくようになっているので、お出かけです。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"114:1-114:51\"\u003e\n\u003cspan id=\"kintoneにたまったデータを可視化する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E3%81%AB%E3%81%9F%E3%81%BE%E3%81%A3%E3%81%9F%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%AF%E8%A6%96%E5%8C%96%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintoneにたまったデータを可視化する\u003c/h1\u003e\n\u003cp data-sourcepos=\"115:1-116:102\"\u003eGoogleマップ上に移動履歴がマッピングされている表示にするには、\u003ca href=\"https://www.tis2010.jp/geocoding/\" rel=\"nofollow noopener\" target=\"_blank\"\u003eTIS住所/緯度経度変換プラグイン\u003c/a\u003eが手軽です。\u003cbr\u003e\n（とはいえ、Google Maps APIキーが必要なので、初めての方には難しいかも…）\u003c/p\u003e\n\u003cp data-sourcepos=\"118:1-118:144\"\u003eプラグインの設定で必須の項目があったので、それに合わせてフィールドの修正や設定の変更をしました。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"119:1-119:19\"\u003e\n\u003cspan id=\"kintoneの設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone%E3%81%AE%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintoneの設定\u003c/h2\u003e\n\u003cul data-sourcepos=\"120:1-123:0\"\u003e\n\u003cli data-sourcepos=\"120:1-120:44\"\u003e住所用のフィールドの追加する\u003c/li\u003e\n\u003cli data-sourcepos=\"121:1-121:47\"\u003e地図表示用のスペースを追加する\u003c/li\u003e\n\u003cli data-sourcepos=\"122:1-123:0\"\u003e緯度・経度を小数点以下9桁にする\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"124:1-124:74\"\u003eこれで表示した2026/4/6のお花見ツーリングの結果です。\u003c/p\u003e\n\u003cp data-sourcepos=\"126:1-126:161\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2Ff4ac5479-d769-4d3c-b4e7-560f092cd736.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=7af42f494d926ba796ea49d1fef25fb6\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2Ff4ac5479-d769-4d3c-b4e7-560f092cd736.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=7af42f494d926ba796ea49d1fef25fb6\" alt=\"スクリーンショット 2026-04-05 172427.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2Ff4ac5479-d769-4d3c-b4e7-560f092cd736.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=856dba40088ca0e3cfede14e63ab4bb5 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/f4ac5479-d769-4d3c-b4e7-560f092cd736.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"128:1-129:105\"\u003e×のあたりはそういえばスマホも使えませんでした。\u003cbr\u003e\n圏外なので、GPSマルチユニットからも送信できなくて、記録なし。なるほど。\u003c/p\u003e\n\u003cp data-sourcepos=\"131:1-131:117\"\u003eなお、この日は桜吹雪の中のツーリングとなりました。一番良かったのはここでした。\u003c/p\u003e\n\u003cp data-sourcepos=\"133:1-133:54\"\u003e\u003ca href=\"https://share.google/VFGSyjzOqBgKQWVQk\" rel=\"nofollow noopener\" target=\"_blank\"\u003e津本公園\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"135:1-135:139\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F0e90a851-9a78-4aaf-bb33-5728289cea6b.jpeg?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=c01bbf2b5ab21c3420f426e80bd2a80e\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F0e90a851-9a78-4aaf-bb33-5728289cea6b.jpeg?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=c01bbf2b5ab21c3420f426e80bd2a80e\" alt=\"PXL_20260405_031408753.jpg\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F497762%2F0e90a851-9a78-4aaf-bb33-5728289cea6b.jpeg?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=157f1a5b4e1f65191229cb506c3833d9 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/0e90a851-9a78-4aaf-bb33-5728289cea6b.jpeg\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n","body":"2026年2月21日、kintone Café 和歌山とSORACOM UGの共催で、SORACOM GPSマルチユニットを使ったハンズオンを開催しました。\n\n「SORACOM GPS マルチユニット のデータを kintone に保存する」、元祖の解説記事はこちらです。\n\nhttps://qiita.com/yukataoka/items/c07b78f5151c29ac8858\n\nノーコードではなく、AWS Lambdaを使ってkintoneにデータを登録する解説記事です。※GPSマルチユニットの設定が詳細に説明されていますので、私の記事で紹介できていないGPSマルチユニットについての設定の確認をするのにお勧めです。\n\nAWS Lambdaを利用した内容の記事とは異なり、ハンズオンでは、ノーコードでいろいろなシステムを連携するiPaaSの一つ「Yoom」を利用して、もっと気軽にノーコードでkintoneへのデータ登録ができる内容になっています。\n\nhttps://kintone-cafe-wakayama.connpass.com/event/376877/\n\nhttps://note.com/open_squid1443/n/nfc68d83b0ad5\n\n当日はGPSマルチユニットの貸し出しがあって、手ぶらで体験できる（言い過ぎでした、パソコンは持参必要です）のですが、自分で移動の履歴がとりたくなってきたので、自分でもGPSマルチユニットを買いました。\n設定は、当日と同じSORACOM→Yoom→kintoneではなく、運営のメンバーのチャットで見かけた「Fluxでできる」という会話をヒントにやってみたものをメモしておきます。\n\n\n\n# kintoneアプリの準備\nあらかじめ、GPSユニットが自動でデータを入れてくれる箱を用意しておきます。\n最低限、これだけ設定しておけばOKです。\n\n## フィールド：フィールドコード\n4つ。数値フィールドです。\nkintoneのフィールドコードは任意に設定できますが、管理を分かりやすくするため、SORACOM Fluxで受信するJSONデータのキー名（プロパティ名）に合わせて設定しています。\n- 緯度：lat\n- 経度：lon\n- 温度：temp\n- 湿度：humi\n\n参考\nHome \u003e スタートガイド \u003e IoT デバイス \u003e GPS マルチユニット SORACOM Edition ユーザーガイド \u003e リファレンス \u003e 送信されるデータフォーマット\n\nhttps://users.soracom.io/ja-jp/guides/iot-devices/gps-multiunit/format/\n\n## APIトークン\nGPSマルチユニットからのデータを外部から登録するために、後で使います。\n- 「レコード追加」の権限\n\n## 高度な設定\n緯度経度が小数点以下の値の桁数が多いので、これを設定しておかないと、デフォルトの4桁より小さい数値がなくなってしまい、詳細な位置情報が取得できなくなってしまいます。\n- 小数部の桁数：8\n\n# SORACOM GPSマルチユニットの設定\nここ、設定画面での設定と、GPSマルチユニットへの反映部分、再起動をしたりして何とかなっていますが、自分ではどうもうまく整理できていないので、省略します。\nたぶん、電源を入れたときに窓際にいると、悩むことは少ないような気がします。\n設定中に、どこにあるか自分がよく迷ったところがわかってきたので、それだけまとめておきます。\n\n## 私が設定中によく迷子になったところ\nSIM単体の設定、SIMグループでの設定、デバイスごと（今回ならGPSマルチユニット）の設定があることがわかれば難しくないのかも…？\n\n### GPSマルチユニットからのデータを見る画面（SORACOM Harvest Data）\nいずれの操作でもOKです。\n  - ☰メニュー \u003e データ収集・累積・可視化 \u003e SORACOM Harvest \u003e Harvest データ　\n  ⇒「リソース▼」でSIMを選択\n  - ☰メニュー \u003e SORACOM Air for セルラー \u003e SIM管理\n  ⇒SIMを✅選択して、「操作▼」から「Harvest Dataを表示」をクリック\n### 定期送信のオンオフや頻度を変えたい（GPSマルチユニットの設定）\n  - ☰メニュー \u003e ガジェット管理 \u003e GPSマルチユニット \u003e デバイス設定変更\n### バイナリパーサーの設定（SORACOM Air for セルラー設定）\n  - ☰メニュー \u003e SORACOM Air for セルラー \u003e SIMグループ　\n  ⇒グループを選択して、右がわ上の方で「SORACOM Air for セルラー設定」をクリック\n### 他サービスへの送信先の設定（SORACOM Beam）\n※SORACOM Fluxの時は使わない\n  - ~~☰メニュー \u003e SORACOM Air for セルラー \u003e SIMグループ~~\n  ~~⇒グループを選択して、右がわ下の方で「SORACOM Beam」をクリック~~\n\nHarvest データで、データが取得できていることが確認できたら、次に進みます。\n  \n# SORACOM Fluxの設定\nGPSマルチユニットのデータをkintoneに送る設定（アプリ）を作ります。\n\n- SORACOM Fluxの設定画面を開く。\n  - ☰メニュー \u003e SORACOM Flux \u003e Flux アプリ\n- 「新しいFluxアプリを作成する」をクリックする\n- 「最初から作成」をクリックし、名前を付ける。\n- 名前を付けたアプリの画面になるので、「チャネルを作成する」をクリックする。\n- 「新しいチャネルを作成」で「IoTデバイス」を選択する。  \n![スクリーンショット 2026-04-06 112346.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/7c0a1598-3b17-49ac-89c3-34c30956fd34.png)\n\n- 名前はそのままか適当に編集し、SIMグループを選択する。\n- Webhookの詳細\n  - HTTPメソッド：POST\n  - URL：https://（サブドメイン）.cybozu.com/k/v1/record.json\n  - HTTPヘッダー：\n    - X-Cybozu-API-Token：先ほどkintoneで用意したAPIトークン\n    - content-type：application/json\n    - HTTPボディ  \n    ![スクリーンショット 2026-04-06 114924.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/1370b5c7-5da4-47da-845c-ca852d089e89.png)\n      - 「application/json」を選択\n      - 中味は下記\n\n\n```\n{\n  \"app\": アプリID,\n  \"record\": {\n    \"temp\": { \"value\": ${payload.temp} },\n    \"humi\": { \"value\": ${payload.humi} },\n    \"lat\": { \"value\": ${payload.lat} },\n    \"lon\": { \"value\": ${payload.lon} }\n  }\n}\n```\n\n\nこれで保存したら、kintoneへの登録が始まっていました。\n\nリクエストの中身をポチポチ選択して作ることができないので、ノーコードとは言えないかもしれないけれど、SORACOM→Yoom→kintoneの設定のときよりも、別サービスとの間で行ったり来たりするのが少ないので、わかりやすいと感じました。\n\nここまでで、kintoneに移動履歴がどんどんたまっていくようになっているので、お出かけです。\n\n# kintoneにたまったデータを可視化する\nGoogleマップ上に移動履歴がマッピングされている表示にするには、[TIS住所/緯度経度変換プラグイン](https://www.tis2010.jp/geocoding/)が手軽です。\n（とはいえ、Google Maps APIキーが必要なので、初めての方には難しいかも…）\n\nプラグインの設定で必須の項目があったので、それに合わせてフィールドの修正や設定の変更をしました。\n## kintoneの設定\n- 住所用のフィールドの追加する\n- 地図表示用のスペースを追加する\n- 緯度・経度を小数点以下9桁にする\n\nこれで表示した2026/4/6のお花見ツーリングの結果です。\n\n![スクリーンショット 2026-04-05 172427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/f4ac5479-d769-4d3c-b4e7-560f092cd736.png)\n\n×のあたりはそういえばスマホも使えませんでした。\n圏外なので、GPSマルチユニットからも送信できなくて、記録なし。なるほど。\n\nなお、この日は桜吹雪の中のツーリングとなりました。一番良かったのはここでした。\n\n[津本公園](https://share.google/VFGSyjzOqBgKQWVQk)\n\n![PXL_20260405_031408753.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497762/0e90a851-9a78-4aaf-bb33-5728289cea6b.jpeg)\n\n","coediting":false,"comments_count":0,"created_at":"2026-04-06T12:51:09+09:00","group":null,"id":"e745434665262d979ff6","likes_count":1,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"GPS","versions":[]},{"name":"kintone","versions":[]},{"name":"SORACOM","versions":[]},{"name":"GPSマルチユニット","versions":[]},{"name":"SORACOMFlux","versions":[]}],"title":"「SORACOM GPS マルチユニット のデータを kintone に保存する」をSORACOM Fluxでやってみた","updated_at":"2026-04-07T11:48:32+09:00","url":"https://qiita.com/kimiko0217/items/e745434665262d979ff6","user":{"description":"勉強のメモに。","facebook_id":"","followees_count":3,"followers_count":0,"github_login_name":null,"id":"kimiko0217","items_count":7,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":497762,"profile_image_url":"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/497762/f1a46afb69ba4e208e942137e81dcce66dad63c4/x_large.png?1775448841","team_only":false,"twitter_screen_name":null,"website_url":"https://blog.studio-fu.com/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:113\"\u003ekintone テンプレートの営業支援パックを使って、顧客ランク別集計を行ってみます。\u003c/p\u003e\n\u003ch1 data-sourcepos=\"3:1-3:8\"\u003e\n\u003cspan id=\"概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e概要\u003c/h1\u003e\n\u003cp data-sourcepos=\"5:1-7:60\"\u003e営業支援パックには、顧客管理アプリ、案件管理アプリ、活動履歴アプリがあります。\u003cbr\u003e\n顧客管理アプリに顧客ランク、案件管理アプリに案件の金額を持っています。\u003cbr\u003e\nこの顧客ランク別に金額を集計してみます。\u003c/p\u003e\n\u003cul data-sourcepos=\"9:1-10:0\"\u003e\n\u003cli data-sourcepos=\"9:1-10:0\"\u003e顧客ランク別集計\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"11:1-11:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F4f3719eb-033e-4cab-8599-384003aa2afd.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=5943d00b9d2125a86ef42d496fcab257\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F4f3719eb-033e-4cab-8599-384003aa2afd.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=5943d00b9d2125a86ef42d496fcab257\" alt=\"2026-04-06_09h23_46.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F4f3719eb-033e-4cab-8599-384003aa2afd.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=5372af3286a3687b617871c6a91a713d 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4f3719eb-033e-4cab-8599-384003aa2afd.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"13:1-14:0\"\u003e\n\u003cli data-sourcepos=\"13:1-14:0\"\u003e顧客管理アプリと案件管理アプリ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"15:1-15:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F387c0ed3-7b81-4bd5-9e04-1d51c795d8c4.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=3747b7e2bf4a71eaed59dff054559698\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F387c0ed3-7b81-4bd5-9e04-1d51c795d8c4.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=3747b7e2bf4a71eaed59dff054559698\" alt=\"2026-04-06_09h14_44.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F387c0ed3-7b81-4bd5-9e04-1d51c795d8c4.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=f9ab852b7ae1a3996ad5caaeaea8e775 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/387c0ed3-7b81-4bd5-9e04-1d51c795d8c4.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"17:1-18:0\"\u003e\n\u003cli data-sourcepos=\"17:1-18:0\"\u003e営業支援パックのアプリ関連図\u003c/li\u003e\n\u003c/ul\u003e\n\u003ciframe id=\"qiita-embed-content__847f522f3d6e4f597bc5c973a2c7a048\" src=\"https://qiita.com/embed-contents/mermaid#qiita-embed-content__847f522f3d6e4f597bc5c973a2c7a048\" style=\"width:100%;\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" data-content='{\"data\":\"graph LR\\n %% アプリの定義\\n App89[\\\"顧客管理 (ID: 89)\\\"]\\n App88[\\\"案件管理 (ID: 88)\\\"]\\n App90[\\\"活動履歴 (ID: 90)\\\"]\\n\\n %% ルックアップ関係\\n App88 -- \\\"ルックアップ (キー: 顧客名)\\\" --\u0026gt; App89\\n\\n %% 関連レコード一覧\\n App89 -. \\\"関連レコード (案件一覧)\\\" .-\u0026gt; App88\\n App89 -. \\\"関連レコード (活動履歴)\\\" .-\u0026gt; App90\\n App88 -. \\\"関連レコード (案件に紐付く活動履歴)\\\" .-\u0026gt; App90\\n\\n %% アプリアクション\\n App89 == \\\"アクション: 新規案件を登録する\\\" ==\u0026gt; App88\\n App89 == \\\"アクション: 活動履歴を登録する\\\" ==\u0026gt; App90\\n App88 == \\\"アクション: 活動履歴を登録する\\\" ==\u0026gt; App90\\n\\n %% スタイルの設定\\n style App89 fill:#f9f,stroke:#333,stroke-width:2px\\n style App88 fill:#bbf,stroke:#333,stroke-width:2px\\n style App90 fill:#dfd,stroke:#333,stroke-width:1px\",\"key\":\"7ff26838a6eba95fbc1ddc6eeade5a24\"}'\u003e\n\u003c/iframe\u003e\n\n\u003ch1 data-sourcepos=\"45:1-45:6\"\u003e\n\u003cspan id=\"ksql\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#ksql\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekSQL\u003c/h1\u003e\n\u003cp data-sourcepos=\"47:1-48:59\"\u003e下記のような SQL で、合計できます。\u003cbr\u003e\n各アプリは、 APP+アプリ番号で指定します。\u003c/p\u003e\n\u003cul data-sourcepos=\"50:1-52:0\"\u003e\n\u003cli data-sourcepos=\"50:1-50:32\"\u003e顧客管理アプリ： APP89\u003c/li\u003e\n\u003cli data-sourcepos=\"51:1-52:0\"\u003e案件管理アプリ： APP88\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"53:1-58:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFORMAT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eSUM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e合計費用\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"s1\"\u003e'#,##0'\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"err\"\u003e合計\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP89\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\n\u003cspan class=\"k\"\u003eINNER\u003c/span\u003e \u003cspan class=\"k\"\u003eJOIN\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP88\u003c/span\u003e \u003cspan class=\"k\"\u003eAS\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e \u003cspan class=\"k\"\u003eON\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\n\u003cspan class=\"k\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e顧客ランク\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch1 data-sourcepos=\"60:1-60:53\"\u003e\n\u003cspan id=\"sql解説顧客ランク別合計費用の集計\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#sql%E8%A7%A3%E8%AA%AC%E9%A1%A7%E5%AE%A2%E3%83%A9%E3%83%B3%E3%82%AF%E5%88%A5%E5%90%88%E8%A8%88%E8%B2%BB%E7%94%A8%E3%81%AE%E9%9B%86%E8%A8%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eSQL解説：顧客ランク別合計費用の集計\u003c/h1\u003e\n\u003cp data-sourcepos=\"62:1-62:228\"\u003eこのクエリは、**「顧客管理」アプリ（APP89）\u003cstrong\u003eと\u003c/strong\u003e「案件管理」アプリ（APP88）**を紐付け、顧客の重要度（ランク）ごとに、これまでの案件の総額を算出するものです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"64:1-64:24\"\u003e\n\u003cspan id=\"1-句ごとの解説\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E5%8F%A5%E3%81%94%E3%81%A8%E3%81%AE%E8%A7%A3%E8%AA%AC\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. 句ごとの解説\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"66:1-66:43\"\u003e\n\u003cspan id=\"select句表示する項目の定義\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#select%E5%8F%A5%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E9%A0%85%E7%9B%AE%E3%81%AE%E5%AE%9A%E7%BE%A9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eSELECT句：表示する項目の定義\u003c/h3\u003e\n\u003cul data-sourcepos=\"67:1-72:0\"\u003e\n\u003cli data-sourcepos=\"67:1-68:112\"\u003e\n\u003cstrong\u003e\u003ccode\u003ea.顧客ランク AS 顧客ランク\u003c/code\u003e\u003c/strong\u003e\n\u003cul data-sourcepos=\"68:5-68:112\"\u003e\n\u003cli data-sourcepos=\"68:5-68:112\"\u003e「顧客管理」アプリにある「顧客ランク」フィールド（A, B, C）を取得します。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"69:1-72:0\"\u003e\n\u003cstrong\u003e\u003ccode\u003eFORMAT(SUM(b.合計費用),'#,##0') AS 合計\u003c/code\u003e\u003c/strong\u003e\n\u003cul data-sourcepos=\"70:5-72:0\"\u003e\n\u003cli data-sourcepos=\"70:5-70:153\"\u003e「案件管理」アプリにある「合計費用」フィールド（プラン費用＋オプション費用の計算値）を合算します。\u003c/li\u003e\n\u003cli data-sourcepos=\"71:5-72:0\"\u003e\n\u003ccode\u003eFORMAT\u003c/code\u003e 関数により、数値を3桁区切りのカンマ形式で整えています。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"73:1-73:39\"\u003e\n\u003cspan id=\"from--join句アプリの結合\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#from--join%E5%8F%A5%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E7%B5%90%E5%90%88\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eFROM / JOIN句：アプリの結合\u003c/h3\u003e\n\u003cul data-sourcepos=\"74:1-78:0\"\u003e\n\u003cli data-sourcepos=\"74:1-75:108\"\u003e\n\u003cstrong\u003e\u003ccode\u003eFROM APP89 AS a\u003c/code\u003e\u003c/strong\u003e / \u003cstrong\u003e\u003ccode\u003eINNER JOIN APP88 AS b\u003c/code\u003e\u003c/strong\u003e\n\u003cul data-sourcepos=\"75:5-75:108\"\u003e\n\u003cli data-sourcepos=\"75:5-75:108\"\u003e「顧客管理」をテーブル \u003ccode\u003ea\u003c/code\u003e、「案件管理」をテーブル \u003ccode\u003eb\u003c/code\u003e として扱います。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli data-sourcepos=\"76:1-78:0\"\u003e\n\u003cstrong\u003e\u003ccode\u003eON a.顧客名 = b.顧客名\u003c/code\u003e\u003c/strong\u003e\n\u003cul data-sourcepos=\"77:5-78:0\"\u003e\n\u003cli data-sourcepos=\"77:5-78:0\"\u003e「案件管理」の「顧客名」フィールドは「顧客管理」からの\u003cstrong\u003eルックアップ\u003c/strong\u003eに設定されているため、このフィールドをキーにして両方のレコードを正確に紐付けています。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"79:1-79:33\"\u003e\n\u003cspan id=\"group-by句集計の単位\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#group-by%E5%8F%A5%E9%9B%86%E8%A8%88%E3%81%AE%E5%8D%98%E4%BD%8D\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eGROUP BY句：集計の単位\u003c/h3\u003e\n\u003cul data-sourcepos=\"80:1-82:0\"\u003e\n\u003cli data-sourcepos=\"80:1-82:0\"\u003e\n\u003cstrong\u003e\u003ccode\u003eGROUP BY a.顧客ランク\u003c/code\u003e\u003c/strong\u003e\n\u003cul data-sourcepos=\"81:5-82:0\"\u003e\n\u003cli data-sourcepos=\"81:5-82:0\"\u003eデータをランク（A, B, C）ごとにグループ化し、ランクごとの合計金額を算出するように指示しています。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr data-sourcepos=\"83:1-84:0\"\u003e\n\u003ch2 data-sourcepos=\"85:1-85:45\"\u003e\n\u003cspan id=\"2-アプリ設計に基づく補足事項\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E3%82%A2%E3%83%97%E3%83%AA%E8%A8%AD%E8%A8%88%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%8F%E8%A3%9C%E8%B6%B3%E4%BA%8B%E9%A0%85\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. アプリ設計に基づく補足事項\u003c/h2\u003e\n\u003cul data-sourcepos=\"87:1-90:0\"\u003e\n\u003cli data-sourcepos=\"87:1-87:247\"\u003e\n\u003cstrong\u003eリレーションの根拠\u003c/strong\u003e: 「案件管理」アプリの設計書を確認すると、\u003ccode\u003e顧客名\u003c/code\u003eをコピー元とするルックアップ設定が存在しており、データの一貫性が保たれていることがわかります。\u003c/li\u003e\n\u003cli data-sourcepos=\"88:1-88:179\"\u003e\n\u003cstrong\u003e集計対象の精度\u003c/strong\u003e: 数値の丸め方は「最近接偶数への丸め」に設定されており、計算精度は16桁（小数部4桁）で管理されています。\u003c/li\u003e\n\u003cli data-sourcepos=\"89:1-90:0\"\u003e\n\u003cstrong\u003eアクションとの関連\u003c/strong\u003e: 「顧客管理」から「新規案件を登録する」アプリアクションを実行して作成されたデータであれば、必ず「顧客名」が一致するため、このSQLで正しく集計されます。\u003c/li\u003e\n\u003c/ul\u003e\n","body":"kintone テンプレートの営業支援パックを使って、顧客ランク別集計を行ってみます。\n\n# 概要\n\n営業支援パックには、顧客管理アプリ、案件管理アプリ、活動履歴アプリがあります。\n顧客管理アプリに顧客ランク、案件管理アプリに案件の金額を持っています。\nこの顧客ランク別に金額を集計してみます。\n\n- 顧客ランク別集計\n\n![2026-04-06_09h23_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4f3719eb-033e-4cab-8599-384003aa2afd.png)\n\n- 顧客管理アプリと案件管理アプリ\n\n![2026-04-06_09h14_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/387c0ed3-7b81-4bd5-9e04-1d51c795d8c4.png)\n\n- 営業支援パックのアプリ関連図\n\n```mermaid\ngraph LR\n    %% アプリの定義\n    App89[\"顧客管理 (ID: 89)\"]\n    App88[\"案件管理 (ID: 88)\"]\n    App90[\"活動履歴 (ID: 90)\"]\n\n    %% ルックアップ関係\n    App88 -- \"ルックアップ (キー: 顧客名)\" --\u003e App89\n\n    %% 関連レコード一覧\n    App89 -. \"関連レコード (案件一覧)\" .-\u003e App88\n    App89 -. \"関連レコード (活動履歴)\" .-\u003e App90\n    App88 -. \"関連レコード (案件に紐付く活動履歴)\" .-\u003e App90\n\n    %% アプリアクション\n    App89 == \"アクション: 新規案件を登録する\" ==\u003e App88\n    App89 == \"アクション: 活動履歴を登録する\" ==\u003e App90\n    App88 == \"アクション: 活動履歴を登録する\" ==\u003e App90\n\n    %% スタイルの設定\n    style App89 fill:#f9f,stroke:#333,stroke-width:2px\n    style App88 fill:#bbf,stroke:#333,stroke-width:2px\n    style App90 fill:#dfd,stroke:#333,stroke-width:1px\n```\n\n# kSQL\n\n下記のような SQL で、合計できます。\n各アプリは、 APP+アプリ番号で指定します。\n\n- 顧客管理アプリ： APP89\n- 案件管理アプリ： APP88\n\n```sql\nSELECT a.顧客ランク AS 顧客ランク, FORMAT(SUM(b.合計費用),'#,##0') AS 合計\nFROM APP89 AS a\nINNER JOIN APP88 AS b ON a.顧客名 = b.顧客名\nGROUP BY a.顧客ランク\n```\n\n# SQL解説：顧客ランク別合計費用の集計\n\nこのクエリは、**「顧客管理」アプリ（APP89）**と**「案件管理」アプリ（APP88）**を紐付け、顧客の重要度（ランク）ごとに、これまでの案件の総額を算出するものです。\n\n## 1. 句ごとの解説\n\n### SELECT句：表示する項目の定義\n* **`a.顧客ランク AS 顧客ランク`**\n    * 「顧客管理」アプリにある「顧客ランク」フィールド（A, B, C）を取得します。\n* **`FORMAT(SUM(b.合計費用),'#,##0') AS 合計`**\n    * 「案件管理」アプリにある「合計費用」フィールド（プラン費用＋オプション費用の計算値）を合算します。\n    * `FORMAT` 関数により、数値を3桁区切りのカンマ形式で整えています。\n\n### FROM / JOIN句：アプリの結合\n* **`FROM APP89 AS a`** / **`INNER JOIN APP88 AS b`**\n    * 「顧客管理」をテーブル `a`、「案件管理」をテーブル `b` として扱います。\n* **`ON a.顧客名 = b.顧客名`**\n    * 「案件管理」の「顧客名」フィールドは「顧客管理」からの**ルックアップ**に設定されているため、このフィールドをキーにして両方のレコードを正確に紐付けています。\n\n### GROUP BY句：集計の単位\n* **`GROUP BY a.顧客ランク`**\n    * データをランク（A, B, C）ごとにグループ化し、ランクごとの合計金額を算出するように指示しています。\n\n---\n\n## 2. アプリ設計に基づく補足事項\n\n* **リレーションの根拠**: 「案件管理」アプリの設計書を確認すると、`顧客名`をコピー元とするルックアップ設定が存在しており、データの一貫性が保たれていることがわかります。\n* **集計対象の精度**: 数値の丸め方は「最近接偶数への丸め」に設定されており、計算精度は16桁（小数部4桁）で管理されています。\n* **アクションとの関連**: 「顧客管理」から「新規案件を登録する」アプリアクションを実行して作成されたデータであれば、必ず「顧客名」が一致するため、このSQLで正しく集計されます。\n\n","coediting":false,"comments_count":0,"created_at":"2026-04-06T09:31:39+09:00","group":null,"id":"bfb0149b57c5da9b4a2f","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"SQL","versions":[]},{"name":"kintone","versions":[]}],"title":"rex0220 kSQL 顧客ランク別集計","updated_at":"2026-04-06T09:43:48+09:00","url":"https://qiita.com/rex0220/items/bfb0149b57c5da9b4a2f","user":{"description":"","facebook_id":"","followees_count":0,"followers_count":150,"github_login_name":"rex0220","id":"rex0220","items_count":594,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":100572,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/100572/profile-images/1473708137","team_only":false,"twitter_screen_name":"rex02201","website_url":"https://rex0220.stores.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false},{"rendered_body":"\u003cp data-sourcepos=\"1:1-1:91\"\u003ekSQL は kintone アプリを SQL ライクな構文で操作するプラグインです。\u003c/p\u003e\n\u003cp data-sourcepos=\"3:1-3:12\"\u003e関連記事\u003c/p\u003e\n\u003cul data-sourcepos=\"5:2-7:0\"\u003e\n\u003cli data-sourcepos=\"5:2-5:96\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/e089fddf4229d74be699\" id=\"reference-854317f97cd8c0c1c478\"\u003erex0220 kSQL 言語リファレンス\u003c/a\u003e\u003c/li\u003e\n\u003cli data-sourcepos=\"6:2-7:0\"\u003e\u003ca href=\"https://qiita.com/rex0220/items/bfb0149b57c5da9b4a2f\" id=\"reference-a7f9a1d636b3e4967205\"\u003erex0220 kSQL 顧客ランク別集計\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 data-sourcepos=\"8:1-8:8\"\u003e\n\u003cspan id=\"概要\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E6%A6%82%E8%A6%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e概要\u003c/h1\u003e\n\u003cp data-sourcepos=\"10:1-10:196\"\u003ekSQLプラグインは、kintoneデータを SQL ライクな書き方で操作でき、SELECT だけでなく 挿入（INSERT）・更新（UPDATE）・削除（DELETE） にも対応します。\u003c/p\u003e\n\u003cp data-sourcepos=\"12:1-12:154\"\u003eAPP100 のようにアプリをテーブル感覚で扱えるため、参照からメンテナンスまでを一貫したクエリで実行できます。\u003c/p\u003e\n\u003cp data-sourcepos=\"14:1-14:106\"\u003eSQLに慣れた人ほど、kintone運用を直感的かつ効率的に進められるのが特長です。\u003c/p\u003e\n\u003cp data-sourcepos=\"16:1-17:44\"\u003eGithub に公開しました。\u003cbr\u003e\n\u003ca href=\"https://github.com/rex0220/kintone-sql-tools\" class=\"autolink\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://github.com/rex0220/kintone-sql-tools\u003c/a\u003e\u003c/p\u003e\n\u003cp data-sourcepos=\"19:1-20:62\"\u003eプラグインとテンプレートファイル\u003cbr\u003e\n\u003ca href=\"https://github.com/rex0220/kintone-sql-tools/tree/main/release\" class=\"autolink\" rel=\"nofollow noopener\" target=\"_blank\"\u003ehttps://github.com/rex0220/kintone-sql-tools/tree/main/release\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"23:1-24:0\"\u003e\n\u003cli data-sourcepos=\"23:1-24:0\"\u003e一覧画面で kSQL 実行\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"25:1-25:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F08253d4b-159d-4992-833b-fc6c7733c14d.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=e7c0f19c5d8e9d943dfbf5f382436404\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F08253d4b-159d-4992-833b-fc6c7733c14d.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=e7c0f19c5d8e9d943dfbf5f382436404\" alt=\"2026-04-05_18h56_42.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F08253d4b-159d-4992-833b-fc6c7733c14d.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=b25b2ee0b61e34fe36b6b240d264a95b 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/08253d4b-159d-4992-833b-fc6c7733c14d.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"27:1-28:0\"\u003e\n\u003cli data-sourcepos=\"27:1-28:0\"\u003e編集画面で  kSQL 実行\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"29:1-29:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F5fc26712-11a6-478b-bf79-cf94ca19c847.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=9f5c754ce6d31b9573070a662c43775f\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F5fc26712-11a6-478b-bf79-cf94ca19c847.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=9f5c754ce6d31b9573070a662c43775f\" alt=\"2026-04-05_20h21_33.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F5fc26712-11a6-478b-bf79-cf94ca19c847.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=925477008bf6f8324e50d9d7212d7d5a 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/5fc26712-11a6-478b-bf79-cf94ca19c847.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"31:1-31:22\"\u003e\n\u003cspan id=\"ksql-専用アプリ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#ksql-%E5%B0%82%E7%94%A8%E3%82%A2%E3%83%97%E3%83%AA\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekSQL 専用アプリ\u003c/h1\u003e\n\u003cp data-sourcepos=\"33:1-34:123\"\u003ekSQL 専用テンプレートから作成します。\u003cbr\u003e\nゲストスペースアプリを参照する場合は、ゲストスペース内にアプリを作成してください。\u003c/p\u003e\n\u003cp data-sourcepos=\"36:1-36:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F55fd9bcc-9a44-47b1-89ff-cb579042f371.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=815aeb039c95c85f8397782017c9ecf6\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F55fd9bcc-9a44-47b1-89ff-cb579042f371.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=815aeb039c95c85f8397782017c9ecf6\" alt=\"2026-04-05_20h26_02.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F55fd9bcc-9a44-47b1-89ff-cb579042f371.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=baf6991e9f9b324b1bd0dca4b1ec5b23 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/55fd9bcc-9a44-47b1-89ff-cb579042f371.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"38:1-38:28\"\u003e\n\u003cspan id=\"ksql-プラグイン設定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#ksql-%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E8%A8%AD%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekSQL プラグイン設定\u003c/h1\u003e\n\u003cp data-sourcepos=\"40:1-40:33\"\u003e設定項目はありません。\u003c/p\u003e\n\u003cp data-sourcepos=\"42:1-42:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F4f789086-760b-451b-8ea7-5b718814a641.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=45b9733b58e6647c9a409fefee59a829\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F4f789086-760b-451b-8ea7-5b718814a641.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=45b9733b58e6647c9a409fefee59a829\" alt=\"2026-04-05_20h40_09.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F4f789086-760b-451b-8ea7-5b718814a641.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=d2ee2f195778df0919c6ef5e483eb905 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4f789086-760b-451b-8ea7-5b718814a641.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"45:1-45:34\"\u003e\n\u003cspan id=\"kintone-画面での-ksql-表示\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#kintone-%E7%94%BB%E9%9D%A2%E3%81%A7%E3%81%AE-ksql-%E8%A1%A8%E7%A4%BA\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekintone 画面での kSQL 表示\u003c/h1\u003e\n\u003cul data-sourcepos=\"47:1-48:0\"\u003e\n\u003cli data-sourcepos=\"47:1-48:0\"\u003e一覧画面\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"49:1-49:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F6cf02e21-4029-4360-872b-1528aaca84b1.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=3f05f408d28d1db39e0c738de477e7ab\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F6cf02e21-4029-4360-872b-1528aaca84b1.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=3f05f408d28d1db39e0c738de477e7ab\" alt=\"2026-04-05_12h01_12.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F6cf02e21-4029-4360-872b-1528aaca84b1.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=e20d3828d7e7ac2817b3dd1a880e4885 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/6cf02e21-4029-4360-872b-1528aaca84b1.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"51:1-52:0\"\u003e\n\u003cli data-sourcepos=\"51:1-52:0\"\u003e一覧画面：オプション表示\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"53:1-53:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F92a43d5f-8cd3-42d8-9328-4b9efa5a661c.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=8b9703b81e553b8607cfc0ef1fc97d95\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F92a43d5f-8cd3-42d8-9328-4b9efa5a661c.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=8b9703b81e553b8607cfc0ef1fc97d95\" alt=\"2026-04-05_12h01_55.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F92a43d5f-8cd3-42d8-9328-4b9efa5a661c.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=2389e017b66b9a904483d262aa48f31a 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/92a43d5f-8cd3-42d8-9328-4b9efa5a661c.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"55:1-56:0\"\u003e\n\u003cli data-sourcepos=\"55:1-56:0\"\u003e追加・編集画面\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"57:1-57:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F31af9e6b-6311-4813-bd45-be44b41685a6.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=7d4d947ba116905f86402f833aa68405\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F31af9e6b-6311-4813-bd45-be44b41685a6.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=7d4d947ba116905f86402f833aa68405\" alt=\"2026-04-05_12h05_15.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F31af9e6b-6311-4813-bd45-be44b41685a6.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=ccce30bd26cedd1e51caf58c356b611f 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/31af9e6b-6311-4813-bd45-be44b41685a6.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul data-sourcepos=\"59:1-60:0\"\u003e\n\u003cli data-sourcepos=\"59:1-60:0\"\u003e詳細画面\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"61:1-61:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fbd57b30d-a25c-4173-ac4d-b1679f569897.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=434abc37d7c15f2ae7c3d0516243f4b4\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fbd57b30d-a25c-4173-ac4d-b1679f569897.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=434abc37d7c15f2ae7c3d0516243f4b4\" alt=\"2026-04-05_12h05_55.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fbd57b30d-a25c-4173-ac4d-b1679f569897.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=8b720c0420ba0bf8f53874ecf17981f4 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/bd57b30d-a25c-4173-ac4d-b1679f569897.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"63:1-63:23\"\u003e\n\u003cspan id=\"オプション指定\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E6%8C%87%E5%AE%9A\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eオプション指定\u003c/h1\u003e\n\u003cp data-sourcepos=\"65:1-65:45\"\u003eタブで切り替えて、設定します。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"67:1-67:24\"\u003e\n\u003cspan id=\"表示オプション\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E8%A1%A8%E7%A4%BA%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e表示オプション\u003c/h2\u003e\n\u003cp data-sourcepos=\"69:1-70:108\"\u003eユーザー選択の名前表示、配列のカンマ区切り、テーブルを行数のみ表示、日時のローカル表示を指定でだいぶ見やすくなります。\u003cbr\u003e\n表示された結果は、フィルター表示・列タイトルクリックでソートが出来ます。\u003c/p\u003e\n\u003cp data-sourcepos=\"72:1-72:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fcf91bf74-302d-40c4-a5be-b602974da1f6.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=3c045461d10cd95ac7c1ed84202abc44\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fcf91bf74-302d-40c4-a5be-b602974da1f6.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=3c045461d10cd95ac7c1ed84202abc44\" alt=\"2026-04-05_12h21_50.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fcf91bf74-302d-40c4-a5be-b602974da1f6.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=4603fc6b4c263526a442742575823d92 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/cf91bf74-302d-40c4-a5be-b602974da1f6.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 data-sourcepos=\"74:1-74:24\"\u003e\n\u003cspan id=\"取得オプション\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%8F%96%E5%BE%97%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e取得オプション\u003c/h2\u003e\n\u003cp data-sourcepos=\"76:1-76:111\"\u003e何件までレコードを取得するかと、オーバー時にエラーまたは続行を指定します。\u003c/p\u003e\n\u003cp data-sourcepos=\"78:1-78:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fd0ab5de0-2480-4680-81a2-cc760a0d6190.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=6b6baa51fac06472cd04731422e01fb7\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fd0ab5de0-2480-4680-81a2-cc760a0d6190.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=6b6baa51fac06472cd04731422e01fb7\" alt=\"2026-04-05_12h26_27.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fd0ab5de0-2480-4680-81a2-cc760a0d6190.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=f9a4061eaff45f296bd4a62f5910d035 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/d0ab5de0-2480-4680-81a2-cc760a0d6190.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 data-sourcepos=\"80:1-80:27\"\u003e\n\u003cspan id=\"保存sqlオプション\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BF%9D%E5%AD%98sql%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e保存SQLオプション\u003c/h2\u003e\n\u003cp data-sourcepos=\"82:1-83:60\"\u003eレコードの内容を表示します。\u003cbr\u003e\nSQLをリセットして元に戻すことが出来ます。\u003c/p\u003e\n\u003cp data-sourcepos=\"85:1-85:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Ff2885766-798f-462d-8bd9-d31f30100e24.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=e72bec4a27517045610ae28c78f169ec\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Ff2885766-798f-462d-8bd9-d31f30100e24.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=e72bec4a27517045610ae28c78f169ec\" alt=\"2026-04-05_12h28_22.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Ff2885766-798f-462d-8bd9-d31f30100e24.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=f2f7158c5370b666caf0c7a7698dc386 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f2885766-798f-462d-8bd9-d31f30100e24.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 data-sourcepos=\"88:1-88:33\"\u003e\n\u003cspan id=\"フィールドオプション\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eフィールドオプション\u003c/h2\u003e\n\u003cp data-sourcepos=\"90:1-91:93\"\u003e指定したアプリのフィールド一覧を表示します。\u003cbr\u003e\nフィールドをクリックすると、SQLにフィールドコードを挿入します。\u003c/p\u003e\n\u003cp data-sourcepos=\"93:1-93:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F204bd29f-cee7-431a-a30e-680284d120c0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=2f0a18010d86ef1662316c4a459ec7aa\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F204bd29f-cee7-431a-a30e-680284d120c0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=2f0a18010d86ef1662316c4a459ec7aa\" alt=\"2026-04-05_12h30_18.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F204bd29f-cee7-431a-a30e-680284d120c0.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=f296b36476bec69066220d4c8c0edd4d 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/204bd29f-cee7-431a-a30e-680284d120c0.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2 data-sourcepos=\"95:1-95:12\"\u003e\n\u003cspan id=\"アプリ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%A2%E3%83%97%E3%83%AA\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eアプリ\u003c/h2\u003e\n\u003cp data-sourcepos=\"97:1-98:83\"\u003eアプリの一覧を表示します。\u003cbr\u003e\nアプリをクリックすると、SQLにアプリ（APPxx）を挿入します。\u003c/p\u003e\n\u003cp data-sourcepos=\"100:1-100:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F00b5d7bd-5621-4cea-88a5-a8216447129e.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=d9dbde861c9215a4d7559305779bbc6e\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F00b5d7bd-5621-4cea-88a5-a8216447129e.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=d9dbde861c9215a4d7559305779bbc6e\" alt=\"2026-04-05_12h32_29.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2F00b5d7bd-5621-4cea-88a5-a8216447129e.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=974a9c00834d5f2e8f43008ebeb1cafb 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/00b5d7bd-5621-4cea-88a5-a8216447129e.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"102:1-102:20\"\u003e\n\u003cspan id=\"テーブル表示\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E8%A1%A8%E7%A4%BA\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eテーブル表示\u003c/h1\u003e\n\u003cp data-sourcepos=\"104:1-104:105\"\u003eテーブルの行数表示指定時、行数をクリックするとテーブル行を表示します。\u003c/p\u003e\n\u003cp data-sourcepos=\"106:1-106:135\"\u003e\u003ca href=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fdef64d7f-8dd3-4925-aea4-3e4f756518fb.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=113dba3e9ce19e2cadac64bae0bf7c80\" target=\"_blank\" rel=\"nofollow noopener\"\u003e\u003cimg src=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fdef64d7f-8dd3-4925-aea4-3e4f756518fb.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;s=113dba3e9ce19e2cadac64bae0bf7c80\" alt=\"2026-04-05_14h20_06.png\" srcset=\"https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F100572%2Fdef64d7f-8dd3-4925-aea4-3e4f756518fb.png?ixlib=rb-4.0.0\u0026amp;auto=format\u0026amp;gif-q=60\u0026amp;q=75\u0026amp;w=1400\u0026amp;fit=max\u0026amp;s=c2b5f2ee76870933efa2dab3987c4562 1x\" data-canonical-src=\"https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/def64d7f-8dd3-4925-aea4-3e4f756518fb.png\" loading=\"lazy\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch1 data-sourcepos=\"108:1-108:19\"\u003e\n\u003cspan id=\"ksql-の使い方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#ksql-%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003ekSQL の使い方\u003c/h1\u003e\n\u003ch2 data-sourcepos=\"110:1-110:24\"\u003e\n\u003cspan id=\"まず最初に試す\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E6%9C%80%E5%88%9D%E3%81%AB%E8%A9%A6%E3%81%99\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまず最初に試す\u003c/h2\u003e\n\u003cp data-sourcepos=\"112:1-113:102\"\u003eプラグインを有効化したあと、対象環境でクエリ実行画面を開いて次を試します。\u003cbr\u003e\nAPP100 の 100 は、アプリID ですので、実際にあるアプリを指定してください。\u003c/p\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"115:1-118:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"120:1-120:35\"\u003e結果が返れば準備OKです。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"122:1-122:21\"\u003e\n\u003cspan id=\"基本の使い方\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%9F%BA%E6%9C%AC%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e基本の使い方\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"124:1-124:37\"\u003e\n\u003cspan id=\"1-必要な列だけ取得する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#1-%E5%BF%85%E8%A6%81%E3%81%AA%E5%88%97%E3%81%A0%E3%81%91%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e1. 必要な列だけ取得する\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"126:1-129:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003eステータス\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"131:1-131:88\"\u003e\u003ccode\u003e*\u003c/code\u003e ではなく列を指定すると、見たい情報に絞って確認できます。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"133:1-133:28\"\u003e\n\u003cspan id=\"2-条件で絞り込む\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#2-%E6%9D%A1%E4%BB%B6%E3%81%A7%E7%B5%9E%E3%82%8A%E8%BE%BC%E3%82%80\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e2. 条件で絞り込む\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"135:1-139:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"err\"\u003eステータス\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003e\"対応中\"\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"141:1-141:68\"\u003e\u003ccode\u003eWHERE\u003c/code\u003e を使うと、対象レコードだけ取得できます。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"143:1-143:37\"\u003e\n\u003cspan id=\"3-更新日時で並び替える\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#3-%E6%9B%B4%E6%96%B0%E6%97%A5%E6%99%82%E3%81%A7%E4%B8%A6%E3%81%B3%E6%9B%BF%E3%81%88%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e3. 更新日時で並び替える\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"145:1-149:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e更新日時\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"err\"\u003e更新日時\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"151:1-151:52\"\u003e\u003ccode\u003eDESC\u003c/code\u003e は新しい順、\u003ccode\u003eASC\u003c/code\u003e は古い順です。\u003c/p\u003e\n\u003ch3 data-sourcepos=\"153:1-153:37\"\u003e\n\u003cspan id=\"4-件数を絞って確認する\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#4-%E4%BB%B6%E6%95%B0%E3%82%92%E7%B5%9E%E3%81%A3%E3%81%A6%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e4. 件数を絞って確認する\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"155:1-160:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003cspan class=\"k\"\u003eLIMIT\u003c/span\u003e \u003cspan class=\"mi\"\u003e20\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003cp data-sourcepos=\"162:1-162:78\"\u003e検証時は \u003ccode\u003eLIMIT\u003c/code\u003e で少件数にすると確認しやすくなります。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"164:1-164:27\"\u003e\n\u003cspan id=\"コピペ用クエリ集\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%B3%E3%83%94%E3%83%9A%E7%94%A8%E3%82%AF%E3%82%A8%E3%83%AA%E9%9B%86\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eコピペ用クエリ集\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"166:1-166:19\"\u003e\n\u003cspan id=\"一覧の基本\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%B8%80%E8%A6%A7%E3%81%AE%E5%9F%BA%E6%9C%AC\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e一覧の基本\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"168:1-172:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003eステータス\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e更新日時\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"err\"\u003e更新日時\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"174:1-174:28\"\u003e\n\u003cspan id=\"対応中だけを見る\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E5%AF%BE%E5%BF%9C%E4%B8%AD%E3%81%A0%E3%81%91%E3%82%92%E8%A6%8B%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e対応中だけを見る\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"176:1-181:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e担当者\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"err\"\u003eステータス\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003e\"対応中\"\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"err\"\u003e更新日時\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch3 data-sourcepos=\"183:1-183:31\"\u003e\n\u003cspan id=\"特定の担当者で絞る\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E7%89%B9%E5%AE%9A%E3%81%AE%E6%8B%85%E5%BD%93%E8%80%85%E3%81%A7%E7%B5%9E%E3%82%8B\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e特定の担当者で絞る\u003c/h3\u003e\n\u003cdiv class=\"code-frame\" data-lang=\"sql\" data-sourcepos=\"185:1-190:3\"\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eSELECT\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003e顧客名\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"err\"\u003eステータス\u003c/span\u003e\n\u003cspan class=\"k\"\u003eFROM\u003c/span\u003e \u003cspan class=\"n\"\u003eAPP100\u003c/span\u003e\n\u003cspan class=\"k\"\u003eWHERE\u003c/span\u003e \u003cspan class=\"err\"\u003e担当者\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003e\"山田 太郎\"\u003c/span\u003e\n\u003cspan class=\"k\"\u003eORDER\u003c/span\u003e \u003cspan class=\"k\"\u003eBY\u003c/span\u003e \u003cspan class=\"err\"\u003eレコード番号\u003c/span\u003e \u003cspan class=\"k\"\u003eDESC\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/div\u003e\n\u003ch2 data-sourcepos=\"192:1-192:33\"\u003e\n\u003cspan id=\"よくあるエラーと対処\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%A8%E5%AF%BE%E5%87%A6\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eよくあるエラーと対処\u003c/h2\u003e\n\u003ch3 data-sourcepos=\"194:1-194:22\"\u003e\n\u003cspan id=\"appxxx-が違う\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#appxxx-%E3%81%8C%E9%81%95%E3%81%86\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\u003ccode\u003eAPPxxx\u003c/code\u003e が違う\u003c/h3\u003e\n\u003cul data-sourcepos=\"196:1-198:0\"\u003e\n\u003cli data-sourcepos=\"196:1-196:74\"\u003eテーブル名は \u003ccode\u003eAPP100\u003c/code\u003e のようにアプリIDで指定します。\u003c/li\u003e\n\u003cli data-sourcepos=\"197:1-198:0\"\u003e対象アプリIDが正しいか確認してください。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"199:1-199:40\"\u003e\n\u003cspan id=\"フィールド名の打ち間違い\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E5%90%8D%E3%81%AE%E6%89%93%E3%81%A1%E9%96%93%E9%81%95%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eフィールド名の打ち間違い\u003c/h3\u003e\n\u003cul data-sourcepos=\"201:1-203:0\"\u003e\n\u003cli data-sourcepos=\"201:1-201:62\"\u003eまず \u003ccode\u003eSELECT * FROM APP100\u003c/code\u003e で項目を確認します。\u003c/li\u003e\n\u003cli data-sourcepos=\"202:1-203:0\"\u003e使いたい列名をそのままコピーして試します。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 data-sourcepos=\"204:1-204:37\"\u003e\n\u003cspan id=\"いきなり大量件数で重い\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%84%E3%81%8D%E3%81%AA%E3%82%8A%E5%A4%A7%E9%87%8F%E4%BB%B6%E6%95%B0%E3%81%A7%E9%87%8D%E3%81%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eいきなり大量件数で重い\u003c/h3\u003e\n\u003cul data-sourcepos=\"206:1-207:0\"\u003e\n\u003cli data-sourcepos=\"206:1-207:0\"\u003e最初は \u003ccode\u003eLIMIT 20\u003c/code\u003e などで小さく試すのがおすすめです。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 data-sourcepos=\"208:1-208:24\"\u003e\n\u003cspan id=\"使い始めのコツ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%81%AE%E3%82%B3%E3%83%84\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e使い始めのコツ\u003c/h2\u003e\n\u003cul data-sourcepos=\"210:1-213:0\"\u003e\n\u003cli data-sourcepos=\"210:1-210:41\"\u003e最初は \u003ccode\u003eSELECT *\u003c/code\u003e で全体を把握\u003c/li\u003e\n\u003cli data-sourcepos=\"211:1-211:20\"\u003e次に列を絞る\u003c/li\u003e\n\u003cli data-sourcepos=\"212:1-213:0\"\u003e最後に \u003ccode\u003eWHERE\u003c/code\u003e と \u003ccode\u003eORDER BY\u003c/code\u003e を足す\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp data-sourcepos=\"214:1-214:102\"\u003eこの順番にすると、クエリのどこで意図とズレたか見つけやすくなります。\u003c/p\u003e\n\u003ch2 data-sourcepos=\"216:1-216:12\"\u003e\n\u003cspan id=\"まとめ\" class=\"fragment\"\u003e\u003c/span\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003e\u003ci class=\"fa fa-link\"\u003e\u003c/i\u003e\u003c/a\u003eまとめ\u003c/h2\u003e\n\u003cp data-sourcepos=\"218:1-219:115\"\u003ekSQLプラグインを使うと、kintoneデータをSQL ライクな書き方で扱えるため、日々の確認や抽出がシンプルになります。\u003cbr\u003e\nまずは \u003ccode\u003eSELECT\u003c/code\u003e / \u003ccode\u003eWHERE\u003c/code\u003e / \u003ccode\u003eORDER BY\u003c/code\u003e の3つを中心に、手元のアプリで試してみてください。\u003c/p\u003e\n","body":"kSQL は kintone アプリを SQL ライクな構文で操作するプラグインです。\n\n関連記事\n\n - [rex0220 kSQL 言語リファレンス](https://qiita.com/rex0220/items/e089fddf4229d74be699)\n - [rex0220 kSQL 顧客ランク別集計](https://qiita.com/rex0220/items/bfb0149b57c5da9b4a2f)\n\n# 概要\n\nkSQLプラグインは、kintoneデータを SQL ライクな書き方で操作でき、SELECT だけでなく 挿入（INSERT）・更新（UPDATE）・削除（DELETE） にも対応します。\n\nAPP100 のようにアプリをテーブル感覚で扱えるため、参照からメンテナンスまでを一貫したクエリで実行できます。\n\nSQLに慣れた人ほど、kintone運用を直感的かつ効率的に進められるのが特長です。\n\nGithub に公開しました。\nhttps://github.com/rex0220/kintone-sql-tools\n\nプラグインとテンプレートファイル\nhttps://github.com/rex0220/kintone-sql-tools/tree/main/release\n\n\n- 一覧画面で kSQL 実行\n\n![2026-04-05_18h56_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/08253d4b-159d-4992-833b-fc6c7733c14d.png)\n\n- 編集画面で  kSQL 実行\n\n![2026-04-05_20h21_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/5fc26712-11a6-478b-bf79-cf94ca19c847.png)\n\n# kSQL 専用アプリ\n\nkSQL 専用テンプレートから作成します。\nゲストスペースアプリを参照する場合は、ゲストスペース内にアプリを作成してください。\n\n![2026-04-05_20h26_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/55fd9bcc-9a44-47b1-89ff-cb579042f371.png)\n\n# kSQL プラグイン設定\n\n設定項目はありません。\n\n![2026-04-05_20h40_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4f789086-760b-451b-8ea7-5b718814a641.png)\n\n\n# kintone 画面での kSQL 表示\n\n- 一覧画面\n\n![2026-04-05_12h01_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/6cf02e21-4029-4360-872b-1528aaca84b1.png)\n\n- 一覧画面：オプション表示\n\n![2026-04-05_12h01_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/92a43d5f-8cd3-42d8-9328-4b9efa5a661c.png)\n\n- 追加・編集画面\n\n![2026-04-05_12h05_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/31af9e6b-6311-4813-bd45-be44b41685a6.png)\n\n- 詳細画面\n\n![2026-04-05_12h05_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/bd57b30d-a25c-4173-ac4d-b1679f569897.png)\n\n# オプション指定\n\nタブで切り替えて、設定します。\n\n## 表示オプション\n\nユーザー選択の名前表示、配列のカンマ区切り、テーブルを行数のみ表示、日時のローカル表示を指定でだいぶ見やすくなります。\n表示された結果は、フィルター表示・列タイトルクリックでソートが出来ます。\n\n![2026-04-05_12h21_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/cf91bf74-302d-40c4-a5be-b602974da1f6.png)\n\n## 取得オプション\n\n何件までレコードを取得するかと、オーバー時にエラーまたは続行を指定します。\n\n![2026-04-05_12h26_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/d0ab5de0-2480-4680-81a2-cc760a0d6190.png)\n\n## 保存SQLオプション\n\nレコードの内容を表示します。\nSQLをリセットして元に戻すことが出来ます。\n\n![2026-04-05_12h28_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f2885766-798f-462d-8bd9-d31f30100e24.png)\n\n\n## フィールドオプション\n\n指定したアプリのフィールド一覧を表示します。\nフィールドをクリックすると、SQLにフィールドコードを挿入します。\n\n![2026-04-05_12h30_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/204bd29f-cee7-431a-a30e-680284d120c0.png)\n\n## アプリ\n\nアプリの一覧を表示します。\nアプリをクリックすると、SQLにアプリ（APPxx）を挿入します。\n\n![2026-04-05_12h32_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/00b5d7bd-5621-4cea-88a5-a8216447129e.png)\n\n# テーブル表示\n\nテーブルの行数表示指定時、行数をクリックするとテーブル行を表示します。\n\n![2026-04-05_14h20_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/def64d7f-8dd3-4925-aea4-3e4f756518fb.png)\n\n# kSQL の使い方\n\n## まず最初に試す\n\nプラグインを有効化したあと、対象環境でクエリ実行画面を開いて次を試します。\nAPP100 の 100 は、アプリID ですので、実際にあるアプリを指定してください。\n\n```sql\nSELECT *\nFROM APP100\n```\n\n結果が返れば準備OKです。\n\n## 基本の使い方\n\n### 1. 必要な列だけ取得する\n\n```sql\nSELECT レコード番号, 顧客名, ステータス\nFROM APP100\n```\n\n`*` ではなく列を指定すると、見たい情報に絞って確認できます。\n\n### 2. 条件で絞り込む\n\n```sql\nSELECT レコード番号, 顧客名\nFROM APP100\nWHERE ステータス = \"対応中\"\n```\n\n`WHERE` を使うと、対象レコードだけ取得できます。\n\n### 3. 更新日時で並び替える\n\n```sql\nSELECT レコード番号, 顧客名, 更新日時\nFROM APP100\nORDER BY 更新日時 DESC\n```\n\n`DESC` は新しい順、`ASC` は古い順です。\n\n### 4. 件数を絞って確認する\n\n```sql\nSELECT レコード番号, 顧客名\nFROM APP100\nORDER BY レコード番号 DESC\nLIMIT 20\n```\n\n検証時は `LIMIT` で少件数にすると確認しやすくなります。\n\n## コピペ用クエリ集\n\n### 一覧の基本\n\n```sql\nSELECT レコード番号, 顧客名, ステータス, 更新日時\nFROM APP100\nORDER BY 更新日時 DESC\n```\n\n### 対応中だけを見る\n\n```sql\nSELECT レコード番号, 顧客名, 担当者\nFROM APP100\nWHERE ステータス = \"対応中\"\nORDER BY 更新日時 DESC\n```\n\n### 特定の担当者で絞る\n\n```sql\nSELECT レコード番号, 顧客名, ステータス\nFROM APP100\nWHERE 担当者 = \"山田 太郎\"\nORDER BY レコード番号 DESC\n```\n\n## よくあるエラーと対処\n\n### `APPxxx` が違う\n\n- テーブル名は `APP100` のようにアプリIDで指定します。\n- 対象アプリIDが正しいか確認してください。\n\n### フィールド名の打ち間違い\n\n- まず `SELECT * FROM APP100` で項目を確認します。\n- 使いたい列名をそのままコピーして試します。\n\n### いきなり大量件数で重い\n\n- 最初は `LIMIT 20` などで小さく試すのがおすすめです。\n\n## 使い始めのコツ\n\n- 最初は `SELECT *` で全体を把握\n- 次に列を絞る\n- 最後に `WHERE` と `ORDER BY` を足す\n\nこの順番にすると、クエリのどこで意図とズレたか見つけやすくなります。\n\n## まとめ\n\nkSQLプラグインを使うと、kintoneデータをSQL ライクな書き方で扱えるため、日々の確認や抽出がシンプルになります。  \nまずは `SELECT` / `WHERE` / `ORDER BY` の3つを中心に、手元のアプリで試してみてください。\n\n","coediting":false,"comments_count":0,"created_at":"2026-04-05T20:31:17+09:00","group":null,"id":"ed9e101cb28b0ed40869","likes_count":0,"private":false,"reactions_count":0,"stocks_count":0,"tags":[{"name":"kintone","versions":[]}],"title":"rex0220 kSQL プラグイン","updated_at":"2026-04-09T14:44:15+09:00","url":"https://qiita.com/rex0220/items/ed9e101cb28b0ed40869","user":{"description":"","facebook_id":"","followees_count":0,"followers_count":150,"github_login_name":"rex0220","id":"rex0220","items_count":594,"linkedin_id":"","location":"","name":"","organization":"","permanent_id":100572,"profile_image_url":"https://qiita-image-store.s3.amazonaws.com/0/100572/profile-images/1473708137","team_only":false,"twitter_screen_name":"rex02201","website_url":"https://rex0220.stores.jp/"},"page_views_count":null,"team_membership":null,"organization_url_name":null,"slide":false}]