2021年6月4日金曜日

ワクチン接種状況ダッシュボードに機能を追加する - 追記

先日に作成したワクチン接種状況ダッシュボードを、もう少々改変した際に使った設定などを追記します。


クラシック・レポートのテンプレート変更


Oracle APEXが提供しているレポート向けのリージョン・タイプは3つあります。クラシック・レポート、対話モード・レポート、対話グリッドです。この中で一番古くから提供されているのがクラシック・レポートです。対話的にレポートの操作をするといった高度な機能は含まれていませんが、テンプレートを変更することによって、レポートではない表示形式に変えることができます。

概要を表示しているレポートの表示を以下に変更しました。


クラシック・レポートのリージョンのAttributesを開き、外観テンプレートとしてValue Attribute Pair - Columnを選択します。テンプレート・オプションのLayoutRight Aligned Detailsを選択することで、数値を右に揃えています。


その他、レイアウト行数のタイプ静的値とし、行数1を指定しています。今回のレポートの表示結果はつねに1行なので、1回のSELECT文の実行でフェッチする行数を1行に制限することは、パフォーマンス上のメリットがあります。

ページ区切りタイプページ区切りなし(すべての行の表示)にしています。テンプレート・オプションにも同様の設定があります。

詳細Pagination Displayを、Hide when all rows displayedに設定すると、必要な時だけページ区切りが表示されます。今回は最初からページ区切りは表示していないので、Defaultから変更していません。


都道府県のセレクタの追加


都道府県のセレクタを追加しました。セレクタを使って都道府県を切り替えたときに、動的アクションとしてJavaScriptを実行し、ページ・アイテムP1_PREFECTUREへの番号の設定と、概要を表示するリージョンのタイトルの設定を行なっています。


Trueアクションとして記載したJavaScriptは以下です。

let sel = $f_SelectedOptions("P1_PREF_SEL");
$s("P1_PREFECTURE", sel.value);
document.getElementById("pref_specific_heading").textContent = sel.text;

選択されている要素を取得するために$f_SelectedOptionsというOracle APEXが提供しているJavaScript APIを使用しています。

例えば、DOMを使って都道府県名を取得するには
document.getElementById("P1_PREF_SEL").options[document.getElementById("P1_PREF_SEL").selectedIndex].text

jQueryを使って選択された都道府県名を取得するには
$f_SelectedOptions("P1_PREF_SEL").text()

といった呼び出しになります。Oracle APEXが前提のコーディングですので、Oracle APEXが提供しているAPIの使用が推奨です。jQueryは便利ですが、一般的なトレンドとして使われない方向になっているので、これからの使用は避けた方がよいでしょう。

Oracle APEXがというよりjQuery自体の話なので、それぞれで判断する必要があります。

動的アクション内での値の設定


上記で都道府県のセレクタを追加しました。都道府県の選択は、新たに追加したセレクタと、対話グリッドの2つになっています。この2つの選択結果を同期させるため、対話グリッドで都道府県を選択したときは、都道府県のセレクタに選択結果を設定するだけにします。

元々のコードは以下でした。(最初の記事ではPREFCODEだった列名はPREFECTUREに変更されています。)

let model = this.data.model;
let record = this.data.selectedRecords[0];
let prefecture = model.getValue(record, "PREFECTURE");
$s("P1_PREFECTURE", prefecture);
document.getElementById("pref_specific_heading").textContent
= model.getValue(record, "PREFECTURE_NAME");

次の様に変更しています。

let model = this.data.model;
let record = this.data.selectedRecords[0];
let prefecture = model.getValue(record, "PREFECTURE");
$s("P1_PREF_SEL", prefecture);

ページ・アイテムP1_PREF_SELの値をOracle APEXのJavaScript API $sを使って変更すると、変更イベントで実行される動的アクションが起動されます。ページ・アイテムP1_PREFECTUREへの値の設定と、リージョンのタイトルpref_sepecific_headingへの文字列の設定は、ページ・アイテムP1_PREF_SELに設定された動的アクションによって実行されます。

デフォルトでは$sによって発生する変更イベントは許可されます。禁止する場合は第4引数にtrueを渡します。

$s("P1_PREF_SEL", prefecture, null, true);

これは、動的アクションのアクションとして値の設定を選んだときの、設定変更イベントの禁止と同じ指定になります。


リフレッシュの抑制


非表示になっているレポートをリフレッシュする必要はありません。動的アクションのTrueアクションにクライアント側の条件を設定することにより、リフレッシュの実行を抑制することが可能です。

リフレッシュを行うアクションのクライアント側の条件タイプJavaScript式を選択し、以下のようなJavaScript式を記述します。

document.getElementById("pref_specific").style.display != "none"

pref_specificはリフレッシュの対象としているリージョンの静的IDです。属性のstyleに含まれているdisplayがnoneでないとき、つまり、リージョンが表示されているときのみリフレッシュを実行します。


アクションクライアント側の条件が設定できるようになったのは、Oracle APEX 21.1からです。

ページ・アイテムP1_GENDERおよびP1_AGEが変更されたときに実行されるリフレッシュに指定します。P1_PREFECTUREには指定しません。

動的アクションは非同期で実行される


全国から都道府県の表示に変わるとき、または、都道府県から全国に表示が変わるときには、いくつかのリージョンが表示から非表示、非表示から表示に切り替わります。

ページ・アイテムP1_PRERECTUREの変更によって呼び出されるリージョンのリフレッシュと、表示の切り替えを行う動的アクションは、それぞれ非同期で実行されるため、どちらが先に実行されるかは判断できません。そのため、P1_PREFECUREの変更で呼び出されるリフレッシュにはクライアント側の条件は付けません。


ボタンB_ALLをクリックすると最初にページ・アイテムP1_PREFECTUREに値を設定します。そのアクションの実行オプションとして結果を待機ONになっています。

これはP1_PREFECTUREへ値が設定されるまで待機する、という動作です。P1_PREFECTUREに設定された動的アクションの実行が完了するまで待機する、という意味ではありません。そのため、リージョンの表示/非表示の切り替えとリージョンのリフレッシュのどちらが先に実行が完了するかは判断できない、ということになります。

処理の順番を決めたい場合は別々のアクションではなく、アクションをひとつのJavaScriptコードの実行として、その中で順番にリージョンの表示/非表示を切り替えるコードおよびリフレッシュを呼び出すコードを記載する必要があります。

リージョン表示セレクタ


Oracle APEXは標準で、リージョン表示セレクタというリージョンを提供しています。


ページに存在するリージョンのプロパティに含まれる詳細リージョン表示セレクタONにすると、リージョン表示セレクタでの操作対象になります。


すべて表示、または、リージョン表示セレクタのプロパティがONのリージョンを選択して表示することができます。

リージョン表示セレクタのAttributesより、いくつかのオプションを設定できます。モード「すべての表示」を含めるなどの切り替えが含まれます。


今回の設定ではリージョンが非表示のときは、リフレッシュを行わない設定にしています。そのため、個別のリージョン、例えば、接種数日次推移を選択している状態からすべて表示に切り替えたときは、接種率日次推移都道府県別接種数 - 接種率は(年代と性別の選択をリージョンが非表示の間に切り替えていると)、非表示なる直前の結果が表示されます。

リフレッシュへのクライアント側の条件を外せば、リージョンが非表示の間もリフレッシュが行われるため、このようなことは発生しません。

リージョン表示セレクタの変更となる動的アクションのタイミングは定義されていません。タイミングにはカスタム・イベントも定義できます。


そこまでの設定は行なっていません。また、このような用途であれば、リージョン表示セレクタではなく、ボタンやチェックボックス・グループを使って、表示するリージョンを選択する機能を実装した方が簡単でしょう。

チャートのズーム


接種数日次推移のチャートにズームとスクロールの機能を追加しました。


チャートのAttributes設定に、ズームとスクロールというプロパティがあります。これにライブを指定しています。


チャートの全画面表示


チャートに限りませんが、テンプレート・オプションShow Maximize Buttonにチェックを入れると、チャートを全画面で表示できるようになります。

外観テンプレート・オプションを開きます。


共通一般に含まれます。


リージョンの最大化ボタンは、右上端に表示されます。


最大化すると、元に戻すボタンに切り替わります。


データに抜けがあるときの対応


チャートAttributesに含まれる、マルチシリーズ・チャート・データギャップをゼロとしてレンダリングOFFにしました。


結果として、チャートが途中で消えることがあります。以下は和歌山県のデータです。



原因は5月9日の2回目の接種が0回で、その日のデータ自体が存在しないためです。今回はチャートに複数のシリーズを作成しているので、マルチシリーズ・チャートになります。

選択肢としては、その日のデータを0として扱うか、nullとして扱うかになります。nullとして扱う様にしたので、チャートが途切れることになってしまいました。しかし、0として扱うよりは良いです。

接種率についてはチャートがつながれば良いだけですが、移動平均を正確に算出するには、データ自体にその日の件数が0であることを示す行が必要です。

今後、2回目の接種が行われない日はそれほどないと予想されるため、特に対応はしていません。

2021年6月3日木曜日

ワクチン接種状況ダッシュボードに機能を追加する

前回作成してみたワクチン接種状況ダッシュボードですが、同じものを作るだけであれば、あまり意味がありません。せっかく手元にデータを持ってきたのですから、少々活用してみました。


ワクチン接種数の7日間移動平均をグラフに追加する

接種数日次推移のグラフに7日間の接種数の移動平均を表示させてみます。

リージョンの接種数日次推移を選択し、Attributesチャートタイプを棒から組合せに変更します。移動平均は棒ではなく、折れ線で表示させます。


シリーズの作成を行います。名前2回目 - (7日間移動平均)とします。タイプ折れ線を選択します。ソースタイプSQL問合せSQL問合せとして以下を記述します。

select
count_date,
avg(count) over (order by count_date asc
range between interval '6' day preceding and current row
) count
from (
select
count_date,
sum(count) count
from covid19_vaccination_results
where status = 2
and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
and age in (select column_value from apex_string.split(:P1_AGE, ':'))
and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
group by count_date
)

元々の接種数の検索結果にSQLのWINDOW関数を適用することで、移動平均を算出しています。

SQLのWINDOW関数の結果をすぐにチャートに表示できるのは便利、と感じるか、SQLで書かなければいけないのか?と感じるかで、Oracle APEXが使えるツールと感じるかどうかの分かれ目になると思います。SQL自体はOracle APEXを使うかどうか、さらにはOracle Databaseを使うかどうかにも関係なく役立てることができる知識なので、難しくても学ぶ価値があります。

送信するページ・アイテムとしてP1_GENDER、P1_AGE、P1_PREFECTUREを指定します。

列のマッピングとして、ラベルCOUNT_DATECOUNTを指定します。外観積上げカテゴリ移動平均2を入力します。移動平均は積み上げ対象から外したいので、単独となる積上げカテゴリにしています。


作成したシリーズ2回目 - (7日間移動平均)重複させます。名前1回目 - (7日間移動平均)に変更します。SQL問合せを以下に変更します。where status = 2の部分をwhere status = 1に変更しています。

select
count_date,
avg(count) over (order by count_date asc
range between interval '6' day preceding and current row
) count
from (
select
count_date,
sum(count) count
from covid19_vaccination_results
where status = 1
and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
and age in (select column_value from apex_string.split(:P1_AGE, ':'))
and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
group by count_date
)

積上げカテゴリ移動平均1に変更します。

元々あったシリーズ1回目2回目を選択し、積上げカテゴリ接種数とします。日次の接種数は積み上げの対象になります。

ページの保存と実行を行うと、接種数日次推移のチャートに、7日間の移動平均を表す折れ線グラフが追加されていることが確認できます。


カラムの値に依存してセルの背景色を変更する

元のダッシュボードは接種率に応じて連続的に背景色を変更しています。Oracle APEXで、それを簡単に実装する方法は見つけることはできませんでした。

その代わりに、段階的に背景色を変更してみます。それぞれの背景色を設定するCSSクラスを定義します。これはページのプロパティのCSSインラインに記載します。CSSクラスは全部で11あります。

.bgdolor-level-100 {
background-color: rgb(0,255,255);
}
.bgcolor-level-90 {
background-color: rgb(25,255,255);
}
.bgcolor-level-80 {
background-color: rgb(50,255,255);
}
.bgcolor-level-70 {
background-color: rgb(75,255,255);
}
.bgcolor-level-60 {
background-color: rgb(100,255,255);
}
.bgcolor-level-50 {
background-color: rgb(125, 185, 185);
}
.bgcolor-level-40 {
background-color: rgb(150,255,255);
}
.bgcolor-level-30 {
background-color: rgb(175,255,255);
}
.bgcolor-level-20 {
background-color: rgb(200,255,255);
}
.bgcolor-level-10 {
background-color: rgb(225,255,255);
}
.bgcolor-level-00 {
background-color: rgb(255,255,255);
}


対話グリッドのリージョン都道府県別接種数 - 接種率を選択し、SQL問合せを以下に変更します。検索結果の列としてCOLORを追加し、接種率が0, 10, 20, ... 100までの11段階に分けてCSSクラスを返すようにします。

with v_first as (
select
prefecture,
sum(count) count
from covid19_vaccination_results
where status = 1
and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
and age in (select column_value from apex_string.split(:P1_AGE, ':'))
and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
group by prefecture
),
v_second as (
select
prefecture,
sum(count) count
from covid19_vaccination_results
where status = 2
and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
and age in (select column_value from apex_string.split(:P1_AGE, ':'))
and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
group by prefecture
),
v_total as (
select
prefecture,
prefecture_name,
sum(count) total
from covid19_vaccination_targets
where 1=1
and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
and age in (select column_value from apex_string.split(:P1_AGE, ':'))
and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
group by prefecture, prefecture_name
)
select
f.prefecture prefecture,
t.prefecture_name prefecture_name,
t.total population,
(f.count + s.count) count_total,
f.count count_first,
(f.count / t.total) * 100 rate_first,
s.count count_second,
(s.count / t.total) * 100 rate_second,
case
when (f.count / t.total) * 100 >= 100 then
'bgcolor-level-100'
when (f.count / t.total) * 100 >= 90 then
'bgcolor-level-90'
when (f.count / t.total) * 100 >= 80 then
'bgcolor-level-80'
when (f.count / t.total) * 100 >= 70 then
'bgcolor-level-70'
when (f.count / t.total) * 100 >= 60 then
'bgcolor-level-60'
when (f.count / t.total) * 100 >= 50 then
'bgcolor-level-50'
when (f.count / t.total) * 100 >= 40 then
'bgcolor-level-40'
when (f.count / t.total) * 100 >= 30 then
'bgcolor-level-30'
when (f.count / t.total) * 100 >= 20 then
'bgcolor-level-20'
when (f.count / t.total) * 100 >= 10 then
'bgcolor-level-10'
else
'bgcolor-level-00'
end color
from v_first f
join v_second s on f.prefecture = s.prefecture
join v_total t on f.prefecture = t.prefecture

COLORが対話グリッドに認識されるので、この列のタイプ非表示に変更します。


列COLORとして返される値を、列RATE_FIRSTにCSSクラスとして適用します。

RATE_FIRSTを選択し、詳細JavaScript初期化コードとして以下を記述します。

function(options){
options.defaultGridColumnOptions = {
cellCssClassesColumn: 'COLOR'
};
return options;
}

対話グリッドの列のプロパティcellCssClassesColumnとしてCOLORを設定しています。これで列COLORの値が、CSSクラスとして列RATE_FIRSTに適用されます。


ページの保存と実行を行うと、1回目接種率のセルの色が異なって表示される都道府県があることが確認できます。



都道府県の概要を表示する


都道府県の選択時に全国の概要ではなく、都道府県の概要を代わりに表示させます。

リージョン全国 - 概要重複させ、名前都道府県概要に変更します。ソースSQL問合せ送信するページ・アイテムはリージョン都道府県別接種数 - 接種率よりコピーします。


追加でレポートに認識された列PREFECTUREPREFECTURE_NAMECOLORタイプ非表示列にします。


追加したリージョン都道府県概要が、検索条件の変更時にリフレッシュされるようTrueアクションの作成をします。

ページ・アイテムP1_GENDERP1_AGEP1_PREFECTUREそれぞれに、アクションリフレッシュのTrueアクションを作成します。影響を受ける要素選択タイプとしてリージョンリージョンとして都道府県概要を指定します。


全国が表示対象のときは全国 - 概要のリージョンだけを表示し、都道府県が選択されているときは都道府県概要のリージョンだけを表示するように設定します。

全国ボタンをクリックしたときに実行される動的アクション都道府県を全選択Trueアクションを3つ追加します。

アクション表示リージョン全国 - 概要初期化時に実行ON
アクション表示リージョン都道府県別接種数 - 接種率初期化時に実行ON
アクション非表示リージョン都道府県概要初期化時に実行ON


次に対話グリッドで都道府県の選択を行ったときに実行される動的アクションを追加します。

最初に、動的アクション都道府県選択クライアント側の条件タイプJavaScript式として、以下のJavaScript式を設定します。

this.data.selectedRecords.length > 0


TrueアクションのJavaScriptコードの実行から、クライアント側の条件を外します。動的アクション自体にクライアント側の条件がついているので、Trueアクションには不要になりました。


全国のボタンをクリックしたときとは反対に、都道府県概要のリージョンだけが表示されるよう、Trueアクションを3つ作成します。

アクション表示リージョン都道府県概要初期化時に実行OFF
アクション非表示リージョン全国 - 概要初期化時に実行OFF
アクション非表示リージョン都道府県別接種数 - 接種率初期化時に実行OFF


この状態でページを実行してみます。全国の表示は以下のようになります。


都道府県を選択すると、以下のようになります。


レイアウトが崩れない様に、リージョンを追加し、全国 - 概要都道府県概要のリージョンを作成したリージョンのサブ・リージョンにします。

リージョンの作成を行い、Content Bodyの先頭に配置します。識別タイトル概要レイアウトとし、タイプ静的コンテンツを選択します。外観テンプレートとしてBlank with Attributesを選択します。


リージョン全国 - 概要および都道府県概要レイアウト親リージョン概要レイアウトに変更します。


以上で全国と都道府県で選択を切り替えても、ページのレイアウトが保持されます。


都道府県概要のタイトル表示を都道府県名にする


都道府県を選択したときのレポートのタイトルが都道府県概要となっており、どの都道府県かわかりません。ここに都道府県名を表示させます。

都道府県概要のリージョンに静的IDを設定します。静的IDpref_specificとします。


都道府県選択を行なったときに実行されるTrueアクションである、JavaScriptコードの実行コードを以下に変更します。末尾に1行追記しリージョンのタイトルに都道府県名を設定しています。

let model = this.data.model;
let record = this.data.selectedRecords[0];
let prefcode = model.getValue(record, "PREFCODE");
$s("P1_PREFECTURE", prefcode);
document.getElementById("pref_specific_heading").textContent
= model.getValue(record, "PREFECTURE_NAME");

idpref_sepecific_headingであるHTML要素のテキスト部分に、都道府県名を代入しています。


今回の作業は以上になります。今まので作業は、公開済みのアプリケーションのエクスポートに含まれています。

作成したアプリケーションは以下よりアクセスできます。

Oracle APEXのアプリケーションの作成の参考になれば幸いです。

2021年6月2日水曜日

ワクチン接種状況ダッシュボードをOracle APEXで作ってみる

 政府CIOポータルより公表されている、ワクチン接種状況ダッシュボードをOracle APEXを使って作ってみました。元のサイトはTabuleauで作っているようです。

ダッシュボードで使用しているデータは、すべてオープンデータとして公開されています。これらのデータの取り込み方法は、以前に記事を書いています。

改行で区切ったJSON(Newline Delimited JSON)のデータをロードする
ワクチン接種数のデータです。表COVID19_VACCINATION_RESULTSにデータをロードしています。公開されているデータの取り込みに表COVID19_DATA_FILESを作成していますが、ダッシュボードの作成には使用していません。

総務省が公表している【総計】令和2年1月1日住民基本台帳年齢階級別人口(市区町村別)のExcelファイルを読み込む
ワクチン接種対象となる人口のデータです。表EGOV_POPULATIONにデータをロードしています。

作成するページは1ページのみです。

以下より、アプリケーションの作り方を紹介します。

最初にワクチン接種の対象となる人数を、都道府県別(PREFECTURE)、男女別(GENDER)、年代(AGE)毎に集計したビューCOVID19_VACCINATION_TARGETSを作成します。以下のDDLを実行します。集計結果はCOUNTになります。

CREATE OR REPLACE FORCE VIEW "COVID19_VACCINATION_TARGETS"
("PREFECTURE", "PREFECTURE_NAME", "GENDER", "AGE", "COUNT") AS
select
trunc(municipality_code/10000) prefecture,
prefecture_name,
gender,
'-64' age,
(age00+age05+age10+age15+age20+age25+age30+age35+age40+age45+age50+age55+age60) count
from egov_population
where city_name is null and gender = 'M' and municipality_code is not null
union all
select
trunc(municipality_code/10000) prefecture,
prefecture_name,
gender,
'65-' age,
(age65+age70+age75+age80+age85+age90+age95+age100) count
from egov_population
where city_name is null and gender = 'M' and municipality_code is not null
union all
select
trunc(municipality_code/10000) prefecture,
prefecture_name,
gender,
'-64' age,
(age00+age05+age10+age15+age20+age25+age30+age35+age40+age45+age50+age55+age60) count
from egov_population
where city_name is null and gender = 'F' and municipality_code is not null
union all
select
trunc(municipality_code/10000) prefecture,
prefecture_name,
gender,
'65-' age,
(age65+age70+age75+age80+age85+age90+age95+age100) count
from egov_population
where city_name is null and gender = 'F' and municipality_code is not null
/


PREFECTURE1から47GENDERMFAGE-6465-の値をそれぞれ持ちます。これらの値はNDJSON形式で提供されているワクチン接種のデータに合わせています。

ホーム・ページのみの空のアプリケーションを作成します。アプリケーション作成ウィザードを起動し、名前ワクチン接種状況ダッシュボードとします。アプリケーションの作成を実行します。


アプリケーションが作成されます。編集するページは1 - ホームのみです。


ページ・デザイナでホーム・ページを開き、全国の概要を表示するレポートを作成します。リージョンの作成を行い、タイトル全国 - 概要とします。タイプクラシック・レポートを選択します。ソースタイプSQL問合せとし、以下のSELECT文を記述します。

with v_first as (
select
sum(count) count
from covid19_vaccination_results
where status = 1
),
v_second as (
select
sum(count) count
from covid19_vaccination_results
where status = 2
),
v_total as (
select
sum(count) total
from covid19_vaccination_targets
)
select
t.total population,
f.count + s.count count_total,
f.count count_first,
(f.count / t.total) * 100 rate_first,
s.count count_second,
(s.count / t.total) * 100 rate_second
from v_first f, v_second s, v_total t

1回目の全接種回数はビューv_firstで集計、2回目はv_second、対象者はv_totalで集計しています。人口、接種数と接種率をSELECT文の結果として返しています。


政府のダッシュボードでは、都道府県を選択すると、その選択が表示に反映されます。都道府県ごとの表示は別に実装するので、このレポートではつねに全国の情報を表示しています。

レポートに表示される列の設定を行います。列を選択し、それぞれ見栄えの調整を行います。


POPULATIONには、以下を設定します。
  • 識別
    • タイプ:プレーン・テキスト
  • ヘッダー
    • ヘッダー:人口
    • 位置合わせ:中央
  • レイアウト
    • 列の位置合せ:右
  • 外観
    • 書式マスク:999G999G999G999G990
  • ソート
    • ソート可能:OFF
COUNT_TOTALは、ヘッダー接種数とします。それ以外は列POPULATIONと同じです。
  • ヘッダー
    • ヘッダー:接種数
COUNT_FIRSTは、ヘッダー1回目接種数とします。それ以外は列POPULATIONと同じです。
  • ヘッダー
    • ヘッダー:1回目接種数
RATE_FIRSTは、ヘッダー1回目接種率とします。今までと設定は大体同じですが、書式マスクの指定に小数点2桁を含め、HTML式を使って数値の末尾に%を付けています。
  • ヘッダー
    • ヘッダー:1回目接種率
  • 外観
    • 書式マスク:999G999G999G999G990D00
  • 列の書式
    • HTML式:#RATE_FIRST#%
COUNT_SECONDは、ヘッダー2回目接種数とします。それ以外は列COUNT_FIRSTと同じです。
  • ヘッダー
    • ヘッダー:2回目接種数
RATE_SECONDは、ヘッダー2回目接種率とします。それ以外は列RATE_FIRSTと同じです。
  • ヘッダー
    • ヘッダー:2回目接種率
  • 列の書式
    • HTML式:#RATE_SECOND#%
クラシック・レポートの表示を調整します。Attributes外観テンプレート・オプションを開きます。


Stretch Reportチェックを入れます。また、詳細Pagination DisplayHide when all rows displayedに設定します。結果は1行なのでページネーションの表示は不要です。


ページの保存と実行を行い、今まで作成した内容を確認します。


ダッシュボードを表示する条件を作成します。リージョンの作成を行い、名前条件タイプ静的コンテンツとします。レイアウト新規行の開始OFFにします。


作成したリージョンで、ページ・アイテムの作成を行います。


性別を選択するページ・アイテムには、以下の設定を行います。
  • 識別
    • 名前:P1_GENDER
    • タイプ:ラジオ・グループ
  • ラベル
    • ラベル:性別
  • 設定
    • 列の数:3
    • 選択時のページ・アクション:None
  • LOV
    • タイプ:静的値
    • 静的値
      • 男:M
      • 女:F
      • すべて:M:F:U
      • 実行時にソート:OFF
    • 追加値の表示:OFF
    • NULL値の表示:OFF
  • デフォルト
    • タイプ:静的
    • 静的値:M:F:U
年代を選択するページ・アイテムを作成し、以下の設定を行います。
  • 識別
    • 名前:P1_AGE
    • タイプ:ラジオ・グループ
  • ラベル
    • ラベル:年代
  • 設定
    • 列の数:2
    • 選択時のページ・アクション:None
  • レイアウト
    • 新規行の開始:OFF
  • LOV
    • タイプ:静的値
      • 65歳以上:65-
      • すべて:-64:65-:UNK
      • 実行時にソート:OFF
    • 追加値の表示:OFF
    • NULL値の表示:OFF
  • デフォルト
    • タイプ:静的
    • 静的値:-64:65-:UNK
都道府県を選択するページ・アイテムを作成し、以下の設定を行います。都道府県の選択は対話グリッドから行うため、このページ・アイテムは非表示とします。
  • 識別
    • 名前:P1_PREFECTURE
    • タイプ:非表示
  • デフォルト
    • タイプ:静的
    • 静的値:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47
都道府県の選択をリセットし、すべての都道府県を対象にするボタンの作成を行います。
    • 識別
      • ボタン名:B_ALL
      • ラベル:全国
    • レイアウト
      • ボタン位置:Region Body
      • 新規行の開始:OFF (場所はP1_PREFECTUREの右隣に配置します)
    • 動作
      • アクション:動的アクションで定義
    ボタンB_ALL動的アクションの作成を行います。

    • 識別
      • 名前:都道府県を全選択
    • タイミング
      • イベント:クリック
      • 選択タイプ:ボタン
      • ボタン:B_ALL
    Trueアクションの設定を行います。

    • 識別
      • アクション:値の設定
    • 設定
      • タイプの設定:Static Assignment
      • 値:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47
      • 変更イベントの禁止:OFF
    • 影響を受ける要素
      • 選択タイプ:アイテム
      • アイテム:P1_PREFECTURE
    ページの保存と実行を行い、今まで作成した内容を確認します。


    接種数日次推移チャートの作成を行います。リージョンの作成を実行します。

    • 識別
      • タイトル:接種数日次推移
      • タイプ:チャート
    Attributesタブを開き、チャートの属性を設定します。

    • チャート
      • タイプ:棒
    • 外観
      • 向き:縦
      • 積上げ:ON
    • 設定
      • 時間軸タイプ:有効
    • 凡例
      • 表示:ON
      • 位置:下
    シリーズとして、最初に2回目の接種数を作成します。(デフォルトでシリーズは1つ作成されているので、正しくは作成済みのシリーズの変更です)。


    接種数を集計するSQLは以下になります。

    select
    count_date,
    sum(count) count
    from covid19_vaccination_results
    where status = 2
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by count_date
    • 識別
      • 名前:2回目
    • ソース
      • 位置:ローカル・データベース
      • タイプ:SQL問合せ
      • SQL問合せ:上記
      • 送信するアイテム:P1_GENDER,P1_AGE,P1_PREFECTURE
    • 列のマッピング
      • ラベル:COUNT_DATE
      • 値:COUNT
    シリーズ2回目を重複させ、1回目を作成します。識別名前1回目に変更し、SQLのwhere status = 2の部分をwhere status = 1に書き換えます。

    select
    count_date,
    sum(count) count
    from covid19_vaccination_results
    where status = 1
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by count_date

    y軸の書式少数小数点0書式スケール自動にします。


    ページの保存と実行を行い、今まで作成した内容を確認します。


    接種率日次推移チャートの作成を行います。作成済みの接種数日次推移のチャート・リージョンを重複させます。識別名前接種率日次推移に変更します。チャートを横並びにするため、レイアウト新規行の開始OFFにします。


    チャートタイプ折れ線に変更します。外観積上げOFFにします。


    2回目シリーズSQL問合せを以下に変更します。

    select
    count_date,
    (
    sum(count)
    over (order by count_date asc)
    /
    (
    select sum(count) total
    from covid19_vaccination_targets
    where 1=1
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    )
    )
    rate
    from
    (
    select
    count_date,
    sum(count) count
    from covid19_vaccination_results
    where status = 2
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by count_date
    )

    列のマッピングRATEに変更します。


    1回目シリーズも変更します。SQL問合せはwhere status = 2の部分をstatus = 1に変更しています。列のマッピングRATEに変更します。

    select
    count_date,
    (
    sum(count)
    over (order by count_date asc)
    /
    (
    select sum(count) total
    from covid19_vaccination_targets
    where 1=1
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    )
    )
    rate
    from
    (
    select
    count_date,
    sum(count) count
    from covid19_vaccination_results
    where status = 1
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by count_date
    )


    y軸の書式割合小数点2にします。


    ページの保存と実行を行い、今まで作成した内容を確認します。


    都道府県ごとの接種数、接種率を一覧する対話グリッドの作成を行います。リージョンの作成を行います。識別タイトル都道府県別接種数 - 接種率タイプ対話グリッドを選択します。ソースタイプSQL問合せで、SQL問合せには以下を記述します。

    with v_first as (
    select
    prefecture,
    sum(count) count
    from covid19_vaccination_results
    where status = 1
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by prefecture
    ),
    v_second as (
    select
    prefecture,
    sum(count) count
    from covid19_vaccination_results
    where status = 2
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by prefecture
    ),
    v_total as (
    select
    prefecture,
    prefecture_name,
    sum(count) total
    from covid19_vaccination_targets
    where 1=1
    and gender in (select column_value from apex_string.split(:P1_GENDER, ':'))
    and age in (select column_value from apex_string.split(:P1_AGE, ':'))
    and prefecture in (select column_value from apex_string.split(:P1_PREFECTURE, ':'))
    group by prefecture, prefecture_name
    )
    select
    f.prefecture prefecture,
    t.prefecture_name prefecture_name,
    t.total population,
    (f.count + s.count) count_total,
    f.count count_first,
    (f.count / t.total) * 100 rate_first,
    s.count count_second,
    (s.count / t.total) * 100 rate_second
    from v_first f
    join v_second s on f.prefecture = s.prefecture
    join v_total t on f.prefecture = t.prefecture

    送信するページ・アイテムとして、P1_GENDER,P1_AGE,P1_PREFECTUREを指定します。


    列をそれぞれ選択し、設定を行います。列PREFECTUREヘッダー#、列PREFECTURE_NAMEヘッダー都道府県とします。それ以外は全国 - 概要のレポートと同じヘッダー位置合せ列の位置合せ書式マスクの設定を適用します。タイプはすべて、数値フィールドのまま変更しません。


    対話グリッドのHTML式はクラシック・レポートとは異なるため、接種率に%をつけるためには使用できません。代わりにCSSを使います。

    ページに、インラインで以下のCSSクラスappendPercentSignを定義します。ページのプロパティのCSSインラインに記載します。

    .appendPercentSign::after {
    content: "%";
    }
        

    RATE_FIRSTRATE_SECOND外観CSSクラスappendPercentSignを指定します。


    ページの保存と実行を行い、今まで作成した内容を確認します。


    チャートとレポートは、すべて作成されました。

    これから条件の変更がチャートやレポートに反映されるよう、動的アクションを追加します。

    最初に対話グリッド上で都道府県を選択可能にします。対話グリッドで動的アクションの作成を行います。

    識別名前都道府県選択とします。タイミングイベント選択の変更[対話グリッド]選択タイプリージョンリージョン都道府県別接種数 - 接種率です。


    Trueアクションを選択し、アクションとしてJavaScriptコードの実行を選びます。設定コードには以下を記述します。対話グリッドの行をクリックして選択された都道府県のコードが、ページ・アイテムP1_PREFECTUREに設定されます。

    let model = this.data.model;
    let record = this.data.selectedRecords[0];
    let prefecture = model.getValue(record, "PREFCTURE");
    $s("P1_PREFECTURE", prefecture);

    選択された行が存在するときのみ実行されるよう、クライアント側の条件としてタイプJavaScript式を選び、以下のJavaScript式を設定します。

    this.data.selectedRecords.length > 0

    アクションのクライアント側の条件は、Oracle APEX 21.1の新機能です。


    ページ・アイテムP1_GENDERP1_AGEP1_PREFECTUREが変更されたときに、2つのチャートと1つの対話グリッドがリフレッシュされるよう、動的アクションの作成をします。

    タイミングイベント変更選択タイプアイテムです。アイテムには、ぞれぞれのページ・アイテムを指定します。


    Trueアクション識別アクションリフレッシュです。影響を受ける要素リージョンで、リージョンには接種数日次推移接種率日次推移都道府県別接種数 - 接種率の3つリージョンをそれぞれ別のTrueアクションとして作成します。3つのページ・アイテムすべてにTrueアクションを3つずつ作成します。


    以上でアプリケーションの完成です。作成したアプリケーションは以下の様な動作になります。


    見栄えなどはまだまだ調整の余地はありますが、基本的な機能は実装できていると思います。

    作成したアプリケーションのエクスポートを以下に置きました。
    https://github.com/ujnak/apexapps/blob/master/exports/vaccine-dashboard.sql

    Oracle APEXのアプリケーション作成の参考になれば幸いです。