SQLを用いた検索画面の作り方

博士!!僕はSQLが得意なのですがULTRAではSQLは使えないんですか?

ユーザプログラムを使うことでSQLも使えるぞい

1.ULTRAでSQLを発行しよう

ULTRAでは基本的にDBのデータを操作するSQLを書かなくても、システムを作成することができます。
しかし、OR検索をしたり複数のモデルを結合してデータを取得したりするためには、SQLを書く必要があります。
本章では検索画面にSQLで取得したデータを表示する方法を学ぶことができます。
プログラミングの知識を必要としますが、システムをより実用化させるために、ぜひ覚えてみて下さい。

2.事前準備

2-01.SQLからの取得結果を格納する空モデルを作成する

まずは、 SQLで取得した結果を表示するためのモデル(テーブル)を作成しましょう。
画面左上の入力から\モデル\トランザクション.mdを開き、次のように追記してください。

# 月別入出金表示モデル
​
| 消費者名 | 対象年月 | 入金額 | 出金額 | 差額 |
|---------|---------|--------|-------|------|

2-02. SQLからの取得結果を格納する空モデルを検索する画面を作成する

2-01. SQLからの取得結果を格納する空モデルを作成する 」で作成したモデルを検索する画面を作成します。
検索画面の作り方は、本マニュアルの「チュートリアル 2-3. 検索画面を作ってみよう」や「ULTRAの使い方 検索画面の作り方」を参考に作成してください。

3.月別の入金・出金額を消費者ごとに集計した結果を取得するSQLを発行しよう

3-01.SQLでデータを取得し、作成した空モデルに格納するユーザプログラムを作成

「 2-02. SQLからの取得結果を格納する空モデルを検索する画面を作成する 」で作成した画面の検索ボタンが押されたときに実行されるユーザプログラムを作成します。
\ユーザプログラム\ユーザプログラム.mdに次のように追記し、保存してください。

|月別入出金表示_SQL事後処理 |monthly_deposit_withdrawal.py |monthly_deposit_withdrawal |

解説:
monthly_deposit_withdrawal.pyというPythonファイル内に、月別の入金・出金額を消費者ごとに集計するSQLを発行し、取得結果をテーブルに格納するプログラムを記述します
日本語名は月別入出金表示_SQL事後処理とします

次にPythonを記述していきます。
monthly_deposit_withdrawal.py に次のように書き保存してください。
※記述するSQLは選択したDBに沿って記述してください。
 サンプルではPostgreSQLを利用しています。DBの設定については「開発支援 外部データベースへの接続方法」を参考にしてください。

from django.db.models import Case, Count, IntegerField, Sum, When
from django.db.models.expressions import Window
from django.db.models.functions import Rank

from ultra.models import *

def monthly_deposit_withdrawal(self, request, response, *args, **kwargs):
    # 検索条件の有無を確認
    # GETパラメタが存在し、かつ空白でない場合に検索条件ありと判断
    # name属性の値でGETパラメタに格納されている

    #消費者名
    p_shouhi_sha_mei = None
    #検索条件に消費者名が指定されている場合
    if 'shouhi_sha_mei_exact' in request.GET:
        if request.GET['shouhi_sha_mei_exact']:
            p_shouhi_sha_mei = request.GET['shouhi_sha_mei_exact']
    #対象年月
    p_taishou_toshitsuki = None
    #検索条件に対象年月が指定されている場合
    if 'taishou_toshitsuki_exact' in request.GET:
        if request.GET['taishou_toshitsuki_exact']:
            p_taishou_toshitsuki = request.GET['taishou_toshitsuki_exact']

    # 検索条件の指定に従いWHERE句を構成
    params = []
    whereClause = ''
    #消費者名(あいまい検索)
    if p_shouhi_sha_mei:
        # like句を使用するため%で囲む
        params.append(f'%{p_shouhi_sha_mei}%')
        if whereClause:
            whereClause += ' AND '
        else:
            whereClause = 'WHERE '
        whereClause += 'shouhi_sha_masuta.shouhi_sha_mei LIKE %s'
    #対象年月(完全一致検索)
    if p_taishou_toshitsuki:
        params.append(p_taishou_toshitsuki)
        if whereClause:
            whereClause += ' AND '
        else:
            whereClause = 'WHERE '
        whereClause += "TO_CHAR(kakei_bo_teburu.hidzuke,'YYYY-MM') = %s"

    # SQLを実行する場合は主キー(id)を必ずSELECT句に含める
    sql = f'''
        SELECT 
			      'id' AS id --id
            ,shouhi_sha_masuta.shouhi_sha_mei AS shouhi_sha_mei --消費者名
            ,TO_CHAR(kakei_bo_teburu.hidzuke,'YYYY-MM') AS taishou_toshitsuki --対象年月
            ,SUM(kakei_bo_teburu.nyuukin_gaku) AS nyuukin_gaku --入金額
            ,SUM(kakei_bo_teburu.shukkin_gaku) AS shukkin_gaku --出金額
            ,SUM(COALESCE(nyuukin_gaku,0) - COALESCE(shukkin_gaku,0)) as sagaku --差額
        FROM ultra_kakei_bo_teburu AS kakei_bo_teburu --家計簿テーブル
        INNER JOIN ultra_shouhi_sha_masuta AS shouhi_sha_masuta --消費者マスタ
        ON kakei_bo_teburu."shouhi_sha_ID_id" = shouhi_sha_masuta.id --家計簿テーブル.消費者ID = 消費者マスタ.id
        {whereClause} --上で作成したWHERE句
        GROUP BY shouhi_sha_masuta.shouhi_sha_mei,TO_CHAR(kakei_bo_teburu.hidzuke,'YYYY-MM') --消費者名,対象年月による集計
        ORDER BY shouhi_sha_masuta.shouhi_sha_mei,TO_CHAR(kakei_bo_teburu.hidzuke,'YYYY-MM') --消費者名,対象年月の昇順で取得
    '''

    # SQLを実行し、検索結果(self.object_list)を更新
    self.object_list = tsukibetsu_nyuu_shukkin_hyouji_moderu.objects.raw(sql,params)
    context = self.get_context_data(
        filter=self.filterset,
        object_list=self.object_list,
    )
    return self.render_to_response(context)

解説:
from ultra.models import 対象のモデルをインポートします
※from ultra.models import * で全てのモデルをインポート
※日本語で記述した内容に基づき、ULTRAが自動でモデルのクラスを作成しているため、どのようなクラス名で作成されるかは作成されたアプリケーションをダウンロードし、latest > ultra > models.py を確認してください
request.GET[‘入力フォームのname属性’] 検索条件のフォームの入力値を取得します
params = []  検索条件のフォームの入力値に従って、SQLに渡すパラメータのリストを作成します
whereClause = ”  検索条件のフォームの入力値に従って値が入力されている場合のみ、まとめてWHERE句を構成します
パラメータの部分は%sとして、%演算子による文字列置換を行います
sql = f”’ select ・・・ ”’ 実行するSQLを文字列として指定します
今回のSQLでは、家計簿テーブルと消費者マスタを結合させてデータを取得しています
上記で作成したWHERE句を{ }内に組み込みます
※SQLのSELECT句には必ず「id」を含める必要があります
ultra_テーブル名. 項目名 AS 別名
SELECT句の中のultra から始まるテーブルはモデルで作成したテーブルです
SQLの取得結果とモデルの項目を紐づけるために、 SELECT句の中でAS句を使用し別名を付けています
別名には、 latest > ultra > tables.py からULTRAが自動作成したテーブルの項目名を付ける必要があります
self.object_list = tsukibetsu_nyuu_shukkin_hyouji_moderu.objects.raw(sql,params)
SQLを実行して取得したデータは月別入出金表示モデル(空モデル)に格納されます

ひとつひとつのコードをじっくり見てほしいぞい

3-02.SQLを実行したい画面にユーザプログラムを組み込む

「 2-02. SQLからの取得結果を格納する空モデルを検索する画面を作成する 」で作成した検索画面に、月別入出金表示_SQL事後処理のユーザプログラムを組み込みます。

\ビュー\月別入出金表示.mdを開き、次のように追記し保存してください。

- 検索処理後に「月別入出金表示_SQL事後処理」を実行する。

解説:
検索処理後に「ユーザプログラム」を実行 と記述することで、検索ボタンを押した際にユーザプログラムが実行されます。

4. SQLを実行してみよう

すべての入力が完了したら、 SQLを実行してみましょう。
検索条件を入力して検索ボタンを押すとユーザプログラムのSQLが実行され、月別の入金・出金額を消費者ごとに集計した結果を検索結果として表示します。
独自のSQLを組み込んだ画面を作成できましたね。

SQLが実行できましたね!!

「 ULTRAにプログラムを組み込む 」の学習終了

本章で、ULTRAにプログラムを組み込むの説明は終了となります。
ULTRAにプログラムを組み込むことで、開発者とユーザのお互いにメリットがあることをご確認いただけたかと思います。

全チュートリアルの学習終了

本章を持ちまして、全てのチュートリアルの学習が終了しました。
チュートリアルで学んだことをぜひシステム開発に生かして頂ければと思います。
またチュートリアルで紹介しきれなかった機能に関しましては、本Webマニュアルで都度更新していきますので、ご確認頂ければと思います。

ここまで大変だったじゃろうがよく頑張ったぞい

一緒に勉強してくれてありがとうございました!!

Product by Trancom-ITS