CakePHP4でHasManyされたレコードのカウント

僕は「博多弁でいこう!」というサイトを運用しています。
このサイトは、もう25年くらい前にPerlのcgiで作ったのが最初で、その後、PHPへ移植。
さらに、CakePHP3化し、現在はCakePHP4で運用しています。CakePHP化したのは、勉強のためという意味合いが強いのですが。

このサイトには、掲載している言葉(博多弁)を使っていたかどうかのアンケートがあります。アンケートの内容は、使っていたかどうかの選択と、回答者の生年と性別、それとフリーのコメントからなります。
各言葉はテーブル(words)に、アンケート結果はテーブル(votes)に保存しています。
テーブル(words)は、テーブル(votes)をHasManyしています。

投票結果のページでは、使っていたかどうかの回答について、回答者の生年から算出した年代と性別でグループ分けして、それぞれの人数を表示するようにしています。
https://sunnyday-aki.ssl-lolipop.jp/hakataben/votes/result

それぞれの言葉の投票結果を一気に取得するために、caseステートメントを使用しました。
世代絞り込みのcaseは以下のような感じです。
カラムyesnoは、1で使っていた。0は使っていなかった。
birthyearは生年。西暦の数値です。sexは性別。

$q1 = $query->newExpr()->case()
    ->when( $query->newExpr()->add( [
        'yesno' => 1,
        $query->newExpr()->between('birthyear', '40才の生年', '21才の生年' ),
    ] ) )
    ->then( 1 )->else(0);

上記は、21〜40才で使っていた人を絞り込むcase。

$q2 = $query->newExpr()->case()
    ->when( $query->newExpr()->add( [
        'yesno' => 0,
        'sex' => 1,
        $query->newExpr()->between('birthyear', '60才の生年', '41才の生年' ),
    ] ) )
    ->then( 1 )->else(0);

上記は、41〜60才の男性で使っていなかった人を絞り込むcase。
whenの条件にマッチすると1が、マッチしなければ0が返ってきます。
これらを以下のようにsumで集計すれば、それぞれの言葉の世代別、回答別の人数を算出できます。

$query->select([
     'age20_yes' => $query->func()->sum($q1),
     'age60_m_no' => $query->func()->sum($q2),
 ]);

実際に生成されたSQL文をdebug.kitで確認すると、以下のようになっています。

SUM(
  CASE WHEN (
    yesno = 0 
    AND sex = 1 
    AND birthyear BETWEEN 1983 
    AND 2002
  ) THEN 1 ELSE 0 END
)

※現在、絶賛お仕事募集中です。興味をお持ちのかたは、以下の問い合わせフォームから
https://www.fourthgate.jp/index.php/contact/
から、是非是非ご連絡ください。

カテゴリー: Webコンテンツ パーマリンク