Q193:検索アプリケーションの作り方について
Q193-1:
現在、データベースを検索するメニューを作成しております。
これについて行き詰ってしまい、またご教示頂けます様お願致します。
例えば、
テキストフィールド1
日付入力フィールド(From)〜日付入力フィールド(To)
テキストフィールド2
があるとし、各情報をand条件で検索をかけます。
検索をかけた時にSQL文を流しますので、Select、Fromまでの固定文を文字列格納変数に入れています。
その後のWhere文についてですが、テキストフィールドに入力する文字列は、'%AAAA%'としておき、次の文字列格納変数でAAAAを入力文字に変換すればするようにすれば、文字が入力されていてもいなくても機能すると思いますが、
日付入力フィールドで、
@Fromのみ入力されている場合はWhere文Aを追加
AToのみ入力されている場合はWhere文Bを追加
BFromもToも入力されている場合はWhere文Cを追加
CFromもToも入力されていない場合はWhere文を追加しない
と条件付けする場合、どのように設定すれば良いでしょうか。
A193-1:
1)基本的にはこれまで通り[文字列格納変数]を使って、目的の文字列を作る、ということで結構です。
今回は、まず[テキストフィールド]と[日付入力フィールド]に表示文字列があるかを判定する必要があります。
文字列に関するコンポーネントには、何も入っていないように見えても空(=NULL)ではなく、「空文字」が入っているとお考え下さい。
[文字列格納変数]に文字列を設定すると「文字列の長さを取得する()」ことができますので、長さ0かどうかで、文字列が入力されているか判断できます。
Where句は「指定した文字列と連結して置き換える(String)」で連結していきます。可能な部分は、雛形を用意し置換する方法でも結構です。
項目名、記号、値がそれぞれ違うため、今回は[ファンクション]コンポーネントを使用して、処理を纏めています。[ファンクション]は[サブルーチン]と同じように処理を纏めるものですが、引数が設定でき、後でファンクションの引数を取得して利用できるという特長があります。
2)日付のWhere句は
「SELECT * FROM table WHERE kaisi>='2012/1/1' and shuryo<='2013/12/31'」
という形で、手元のSQLServerでは実行できました。
[日付入力フィールド]の表示文字列をそのまま利用できます。
ただし、SQLServerに格納されているデータは「2012-1-1 00:00」という形式ですので、複数回検索条件を変えて、お手元のSQLServerで目的のデータが取得できるかご確認下さい。
3)日付の入力を簡単にする部品として[日時選択ダイアログ/パネル]があります。関連ファイルの中でラベルをクリックすると表示されるようにしてあります。属性(TimeInvisible=true)を変更し、月日だけの表示ですが、やや大きめな画面です。
4)データの絞込みは[テーブルサブセットフィルタ]でも行うことができます。
Select文を何回も実行することで、煩雑になる場合には、ある程度の大きさのデータをSelectしておき、メソッド「列データの文字列で行を選択する(int,String)」「列データの日時で行を選択する(int,Date,boolean,Date,boolean)」で絞り込みます。
関連ファイルをご覧頂き、日付の入力やデータの絞込み、その他ご要望がございましたら、再度お知らせ下さい。どうぞよろしくお願い申し上げます。
関連ファイル:日付を含むWhere文作成.mzax
Q193-2:
本件、目的のものが作成できそうです。ありがとうございます。これを参考に下記2点は自力で作成しようと思いましたが、方法が分かりませんでした。またご教示頂けますでしょうか。
@これまでの内容に加え、
・コンボボックスに値が表示されていれば、Where句を追加。空欄ならWhere句の追加はなし(初期値は空欄)
・チェックボックスにチェックが入っていればWhere句を追加。空欄ならWhere句の追加はなし
(コンボボックスのデータは、0、1、2、3と並んでいる場合もあれば、10、26、17、90との場合もあります)
この設定を加えるにはどうすれば良いでしょうか。加えて、下記の追加質問をお願い致します。
A現在作成しようとしている検索画面では、テーブルに結果を表示させる予定です。
例えば、テーブルに5行複数列のデータが表示されたとして、ある行をクリックすると、その行のA列のデータを、テキストフィールドに展開させるには、どのような設定が必要でしょうか。
A193-2: > @これまでの内容に加え、
> ・コンボボックスに値が表示されていれば、Where句を追加。空欄ならWhere句の追加はなし(初期値は空欄)
> ・チェックボックスにチェックが入っていればWhere句を追加。空欄ならWhere句の追加はなし
チェックボックスは「選択状態の有無を取得する()」を実行すると「true/flase」の値が取得できます。その値を[等価演算]等に設定し、イベント番号を付けて、Where句作成の処理を行うかどうか条件分けをします。
コンボボックスも演算コンポーネントの判定の処理を通すという考え方は同じです。
コンボボックスの「現在選択されている項目位置を取得する」と位置番号(0,1,2...)が取得できます。選択状態でないときには「-1」が取得されます。
これを利用して「選択位置>-1かどうか」(=選択されているか)の判定ができます。
また、「選択されている項目のラベル」に着目した場合、選択されている項目が無いと返ってくる値は空(NULL)ですので、前回ご紹介した文字列長さを取得して判定をする処理の前に、[NULL判定]の処理を追加することで、判別可能です。
[コンボボックス]の選択位置を利用する場合には必要ないですが、今回の処理以外にも、全般的に値が入っているか判別する場合「NULLでないか、空文字でないか」を見ていくことになります。ご参考までにこちらもご紹介します。
前回のファイルに処理を追加しましたので、どうぞご覧下さい。
なお、値が数値の場合、データ型を考えると「Where ID=1」のように「']で囲まない方が正式ですが、「Where ID='1'」でも動作します。
処理が少し複雑になりますが「値が数字(数値)の場合、''を付けない」ようにすることも可能ですので、ご希望があればご連絡下さい。
> A現在作成しようとしている検索画面では、テーブルに結果を表示させる予定です。
> 例えば、テーブルに5行複数列のデータが表示されたとして、ある行をクリックすると、その行のA列のデータを、テキストフィールドに展開させるには、どのような設定が必要でしょうか。
現在は例えば、繰返し処理の現在値などで行位置を指定して行データを一行分取得し、それを[オブジェクトキュー]などに設定し、さらに[テキストフィールド]に設定する処理を行っていらっしゃると思います。これを例えば以下のように変更します。
[テーブル]---データ選択イベント---[テーブル]
|「指定行の行データをリスト形式で取得する(int)」
| 取得方法:メソッド戻り値
| コンポーネント:テーブル
| メソッド/値:選択行位置を取得する
| イベント番号:1
|
|------[オブジェクトキュー]
「リストによるキューの設定(PFObjectList)」
取得方法:メソッド処理結果
というような処理になります。
[テーブル]を選択するとデータ選択イベントが発生します。このタイミングで選択行のデータを取得します。
念のため[実行設定可]で実行し、[テーブル]を右クリック>[テーブル]>[選択方法]>[行選択]として、イベント番号1を上記の処理に設定して下さい。
一行全体が選択された方が、選択箇所がユーザーに分かりやすいかと思います。
もし、0列目のセルデータのみを一つの[テキストフィールド]に表示して終わりであれば、一行分のデータを取得する必要は無く、メソッドは「指定セルの値を取得する(int,int)」(引数は選択行位置、選択列位置)となります。
関連ファイル:Where文作成B.mzax、Where文作成C.mzax
Q193-3:
コンボボックスの件で、関連した質問をお願い致します。
現在作成しようとしている検索画面ですが、画面起動(フレームを表示する)と同時にSelect文を流し、画面内のあるコンボボックスに、リスト内容として表示できるようにしたいと考えております。
Select文の結果が、下記の内容であった場合、
A列 B列
1行目 10 0
2行目 20 0
3行目 30 0
A列データの内容をコンボボックスのリスト内容として表示させるにはどうすれば良いでしょうか。
行数は、アプリケーションを運用していく上で、増加致します。
現在、下記内容のものを作成しています。
検索画面起動ボタン------------------フレーム
| メソッド:フレームを表示する
|
|------------------データベースアクセス
| メソッド:SQL文を実行する
|
|------------------?(コンボボックスの前に何か必要か)
|
|------------------コンボボックス
?妥当なメソッドは何か
FAQに似たような目的の記事が何件かありましたが、メソッドや構成の順番がよくわかりませんでした。
本日の質問が分散してしまい申し訳ありませんが、Aにつきまして、下記2点、ご教示頂きます様お願致します。
1.機能はうまく作成する事ができました。ありがとうございます。
この検索画面は、ユーザー情報入力画面や、サポート対応入力画面で、「お客様avという情報のみを検索するための、入力補助目的で作成しております。
複数のメニュー画面で用いたいと思っておりますので、複合コンポーネントを利用しようと考えていますが、チュートリアルなどから理解に至らず、ご教示頂けませんでしょうか。
複合コンポーネントを用いる場合、ご返答頂きました下記内容を、複合コンポーネント内に作成するかと思いますが、
[テーブル]---データ選択イベント---[テーブル]
|「指定行の行データをリスト形式で取得する(int)」
| 取得方法:メソッド戻り値
| コンポーネント:テーブル
| メソッド/値:選択行位置を取得する
| イベント番号:1
|
|------[オブジェクトキュー]
|「リストによるキューの設定(PFObjectList)」
| 取得方法:メソッド処理結果 |
このキューの処理の内容を、階層の異なる画面に持っていく方法として、具体的にどのような設定になりますでしょうか。
2.テーブルに表示された内容ですが、ワンクリックして選択されるのはそのままで、ダブルクリックすると、画面を閉じたりなど、次の処理に移すようにする事は可能でしょうか。
A193-3:
[コンボボックス]にはリスト型のデータを設定することができます。[テーブル(格納変数)]から一列/一行のみデータを取得すると、リスト型のデータとなりますので、[テーブル]から一列取ってそのまま[コンボボックス]に設定するというイメージで結構です。
例えば、[サブルーチン]、[テーブル格納変数]を新規に追加し
[サブルーチン]---アクションイベント---[データベースアクセス]
| 「SQL文を実行する(String)」
| 固定値:SELECT A列 FROM table
|
|----------[テーブル格納変数]
| 「テーブルを設定する(PFObjectTable)」
| 取得方法:メソッド処理結果
| メソッド/値:SQL文を実行する
|
|----------[テーブル格納変数]
| 「列データリストを位置指定で取得する()」
| 取得方法:固定値
| メソッド/値:0
|
|----------[コンボボックス]
「全項目のラベル名を設定する(PFObjectList)」
取得方法:メソッド処理結果
メソッド/値:
列データリストを位置指定で取得する
とします。
この[サブルーチン]を「検索画面起動ボタン」に繋ぎ、メソッド「処理を呼出す()」を設定します。
[テーブル格納変数]にはA列一列分のテーブルデータが入り、それを列指定で取出し、[コンボボックス]に設定するという考え方です。もちろんB列のデータも後で利用する予定があればSQL文は「SELECT A列, B列 FROM table」などとし、一緒にSelectして構いません。
[データベースアクセス]のSelectの結果を[テーブル(格納変数)]に設定するタイミングは2点あります。
@[データベースアクセス]「データ生成イベント」に[テーブル]を繋げる
引数はイベント内包、イベント対象データ
A[データベースアクセス]「SQL文を実行する(Stirng)」が繋がっている同じイベントに[テーブル]を繋げる
引数はメソッド処理結果
どちらでも把握しやすい方で設定して頂いて結構です。
Aの場合、結果が返ってこないSQL(Update文)を実行したり、Select文に誤りがあったりすると、[テーブル]にデータを設定する処理がエラーとなってしまいますが、今回の場合エラーの恐れは少ないかと思います。
なお、「検索画面起動ボタン」には「フレームを表示する()」の前に、上記の処理を繋げて下さい。画面構成部品には画面表示前にデータを設定しておいて、後から画面を開くという考え方です。
[コンボボックス]のデータクリアのメソッドは「removeAllItems()」です。
[データベースアクセス]、[テキストフィールド]が上位の階層に、[テーブル]及び検索Select文作成機能が複合コンポーネント内にあると仮定して回答致します。
もし使用するコンポーネントや配置位置が違う場合には、処理が違ってくる場合がありますので、再度ご連絡下さい。
1)
@複合コンポーネント内のコンポーネントのメソッドは「公開」して利用します。
メソッドの公開については『開発チュートリアルLesson12』で紹介していますので、ご覧下さい。
A複合コンポーネント内で発生したイベントを上位の階層に伝えるには、イベントの接続先を複合コンポーネント(引数:取得方法:イベント)とし、上位の階層で複合コンポーネントにイベント処理を追加します。イベントは複合コンポーネント内で伝播したイベントと同じものを選びます。
<例)複合コンポーネント内のフレームを閉じるとアプリケーション終了>
(複合コンポーネント内)
[フレーム(複合内)]---アクションイベント---[複合コンポーネント]
「イベントを伝播させる(PFEvent)」
取得方法:イベント
(上位階層)
[複合コンポーネント]---アクションイベント---[アプリケーション]
「アプリケーションを終了する()」
Bイベントと一緒に何かデータを伝播したい時には、[イベント生成]コンポーネントを使用します。例えば『複合コンポーネント内のボタンを押したら、SQL文を上位の階層に伝えたい』時などは、ボタンからはアクションイベントしか発生・伝播しませんので、[イベント生成]で引数有りのイベントを意図的に発生させます。関連ファイルで使用していますので、ご覧下さい。
発生させるイベントは適当と思われるもので結構です。
上位の階層では発生させたものと同じイベントに処理を繋げます。
C逆に上位の階層から引数有りで、複合コンポーネント内の処理を呼出したい場合には、添付のファイルでは使っていませんが、[ファンクション]を使用することが多いです。
例えば「上位の階層にある2つの数値を、複合コンポーネント内の計算処理を通て計算させる」場合、「ファンクションの呼出し(2引数)」のメソッドを公開し、上位の階層でこのメソッド呼び出し時に引数を設定し、複合コンポーネント内部ではファンクションの引数を値として使用します。
『データベースアクセスチュートリアル』や『複合コンポーネントチュートリアル』がご参考になるかと思いますので、宜しければご覧下さい。
2)画面構成部品をダブルクリックした時に特に何か処理を行いたい場合には[マウスボタンイベントフィルタ]を使用し、ボタンやクリックの種類、回数などのフィルタを追加して、選別することができます。
加えて[テーブル]の場合、通常はダブルクリックするとセルが編集状態になるので、編集不可にしておく必要があります。
関連ファイルに[テーブル]をダブルクリックすると「フレームを閉じる」処理を設定してありますので、ご覧下さい。
ご検討頂き、ご不明な点、ご要望等ございましたら、再度ご連絡頂ければ幸いです。どうぞよろしくお願い申し上げます。
関連ファイル:複合コンポーネント内のデータ.mzax
Q193-4:
本件、教えて頂いた方法で実現できました。今まではっきりしなかったイベントの運用方法も理解が深まり、ありがとうございます。
ところで、検索画面を作成する途上で入力した、日付のクリアがうまくできず、教えて下さい。日付を設定する(object)で固定値を空欄として作成しているのですが、機能しません。実行(設定可)画面上に日付が表示されたままになっていますが、Deleteキーで削除しても、カーソルを移動すると削除前の状態に戻ってしまいます。原因は何が考えられるでしょうか。
A193-4:
大変紛らわしくて申し訳ないのですが、空の値を設定する際に、NULLを設定するものと空文字を設定するものとがございます。
メソッドには()の中に文字が入っているものがありますが、「String」は文字列を意味し、「〜設定する(Stirng)」というようなメソッドの場合、文字列で値を設定することができます。
「Object」は、そのコンポーネントやメソッドに適した値(オブジェクト)を用いることになります。
日付型のデータは文字列ではなく、日付の情報のかたまりとお考え下さい。
「日付を設定する(Object)」では空文字ではなくNULLを設定して頂くことになります。
引数の設定の際、「取得方法:固定値」でキーボードから「メソッド/値」欄に何も入力をしないのが、NULLの設定方法なのですが、
・「メソッド/値」欄に文字を一度でも入力すると、以後何も入力されていなくても「空文字」となります。
・メソッド/値欄に全く入力をしなければNULLになります。
・「空文字」になってしまった「メソッド/値」欄をNULLに戻すには右クリックし、メニューから「NULL設定」を選びます。
設定した空文字が有効でない、また、フォーカスを移動すると前に確定した値に戻ってしまう理由ですが、[テキストフィールド]以外のフィールド類は、受け付けられない不正な値が設定されても確定されず、先に確定されていた値のままになります。また、キーボードから[日付入力フィールド]の文字をDeleteしても、これは空文字ですので、不正な値ということになり、フォーカスが移動した際デフォルトの挙動では、確定済みの値に表示が戻ります。
[日付入力フィールド]の場合、表示を消したい場合は、「日付を設定する(Object)」で引数は「NULL」となります。
用途に応じて、表示を消すのではなく現在日時を設定したりする場合もございます。
NULLと空文字の設定の判別は紛らわしく、またチュートリアル等での説明も充分でないため、ご不明な点がございましたら、ご連絡頂ければ幸いです。
Q193-5:
本件、右クリック→NULL設定で解決しました。ありがとうございます。
何度も申し訳ありませんが、Where文設定について1点、他2点の事について、またご教示下さい。
@コンボボックスが、初期表示のまま未選択(空欄)の状態であった場合、Where句を追加(入力されている場合は別のWhere句を追加)
頂いた「Where文作成C」を参考に考えましたが、これまで「空欄の場合はWhere句追加なし」の場合のみでしたので、わかりませんでした。
比較演算の<か、>か、等価演算のどれかが追加の起点になるとは思うのですが、どのように設定すれば良いでしょうか。
ASelect文で取得した文字列を、あるラベルに展開しています。
その表示のされ方ですが、文字列が空欄の時は空欄で表示されますが、「Null」の時に、ラベルの初期表示である、<ラベル>との表示になってしまいます。
「Null」データ表示時も空欄で表示させることはできますでしょうか。
Bデータベースへのデータ更新についてですが、レコード追加であれば「新規追加」ボタンにてボタン押下時にINSERT INTO文が流れるようにし、既存データの更新であれば、「更新登録」ボタンにてボタン押下時にUPDATE文が流れるようにしようと考えています。
現行の管理システムでは、「登録ボタン」ひとつのみで、新規登録か更新かはプログラムが判断して、流すSQL文を切り分けているのですが、MZプラットフォームではこのような事は可能でしょうか。
A193-5:
> @コンボボックスが、初期表示のまま未選択(空欄)の状態であった場合、Where句を追加
前回[コンボボックス]の選択位置を手掛かりとして処理を振り分けるものと、選択状態でない時には「選択されている項目のラベル」はNULLであることに着目して振り分けるものとを、サンプルファイルとしてご紹介しました。
選択状態でなくてもWhere句を作成したい場合には、選択位置を手掛かりとした「Where文作成B.mzax」の方が修正しやすいかと思います。
理由としては、[コンボボックス]はユーザーが自分で未選択状態に戻せるように、先頭に空欄などを設けた方が、個人的には使い易いと考えております。
空欄のラベルはNULLではなく空白文字になってしまいます。NULLや文字列長さを手掛かりとして「Where句作成無し」に振り分ける処理と混ざらない方が把握しやすいかと存じます。
2つのファイルを修正してみましたので、ご覧下さい。
考え方としては、選択位置>−1かどうか、またはNULLかどうかの判定を通った後、前回は一方の結果の際の処理しか設定していませんでしたが、trueの時の処理とflaseの時の処理と両方用意するというものです。
AラベルのテキストにNULL値を設定すると、どうしても初期値<ラベル>に戻ってしまいます。気になるようでしたら、「設定しようとする値がNULLだったら、空白文字列を設定する」というNULL判定の処理を加えて頂くことになります。
> B 現行の管理システムでは、「登録ボタン」ひとつのみで、新規登録か更新かはプログラムが判断して、流すSQL文をきりわけているのですが、MZプラットフォームではこのような事は可能でしょうか。
MZPlatformでも、何かしらの判断基準(例:登録するデータと同じID番号があるかどうか)があれば、Insertを行うかUpdateを行うか処理を選択することは可能です。
例えばID=30に該当するデータがあるかSelectすると分かりますので、あればUpdate、無ければInsert文を実行するよう振分けるという考え方です。
現行のシステムも全く自動的にではなく、何かしらの主キーや操作手順等を手掛かりとして判定していると推測します。
お使いのシステムのSQL文や操作順で、手掛かりとなりそうなところはないか、宜しければお探し下さい。
もし完全に手掛かり無しの場合でも、UpdateやInsertを切り分けているように見せることも可能です。それは追加前に既存のデータを削除してしまうというものです。
@ ID=30 氏名=産総太郎 住所=茨城県
A ID=31 氏名=産総花子を追加
追加の前にID=31の削除を行う 該当データ・削除なし
B ID=30 氏名=産総太郎 住所=東京都を追加
追加の前にID=30の削除を行う
ID=30は削除・追加され、以前のデータと比べ住所だけが変わっている
但しこの手法はあまり多くは使われていないと思います。
ご不明な点、ご要望等ございましたら、再度ご連絡下さい。
どうぞよろしくお願い申し上げます。
関連ファイル:Where文作成D.mzax(Bを変更)、Where文作成E.mzax(Cを変更)
Q193-6:
ご返答頂きました、Aにつきまして、下記内容を試してみましたが、機能しませんでした。考え方が違っていると思うのですが、どのように修正すれば良いか、教えて頂けますでしょうか。
1.まず、下記を作成
NULL判定--------------------ラベルAの文字列を設定する(空欄)
(イベント1)
2.ラベルの位置ですが、SQL文を実行してオブジェクトキュー、サブルーチンに納めた状態で、下記のようになっています。
サブルーチン-------------------------ラベルA
(ラベルのテキスト文字列を設定する)
(オブジェクトの取得)
3.下記のように作れば良いかと思いましたが、不正解のようです。
サブルーチン-------------------------ラベルA
| (ラベルのテキスト文字列を設定する)
| (オブジェクトの取得)
|
|-------------------NULL判定
オペランド設定後演算
引数:ラベルA ラベル
テキストを取得
お手数ですが、よろしくお願致します。
A193-6:
『値を取出してみて、空(NULL)でなければ、そのまま設定。空(NULL)だったら、空文字に変えて設定』という考え方になりますので、
値を取出して、ラベルに設定する前に、[NULL判定]します。
次のようになります。
サブルーチン-------------------------NULL判定
オペランド設定後演算
(オブジェクトの取得)
NULL判定--------------------ラベルAの文字列を設定する(空欄)
| (イベント1)
|
|----ラベルAの文字列を設定する(オブジェクト)
メソッド戻り値:NULL判定:
オペランドを取得する
(イベント0)
ここで大変トリッキーなのですが、[オブジェクトキュー]の中の[ラベル]用の値(オブジェクト)はNULL判定の引数として取出されてしまったので、既に[オブジェクトキュー]の中にはありません。従って[NULL判定]のオペランドの値を、NULLでなかった場合のラベルのテキスト文字列として利用することになります。
他にも処理設定の方法はありますが、[等価演算(=)]等のオペランドに一旦設定した値を、判定後に利用することがたまにあります。
もし把握し難ければ別の処理の流れを検討致しますので、ご連絡下さい。
NULLの判定が上手くいかなかった理由ですが、一旦[ラベル]のテキストとしてNULLを設定してしまうと、ラベルのテキスト文字列は『<ラベル>』になります。
ラベルのテキストにはNULLは設定できますが、NULLを取出すことはテキスト(文字列)なので、できません。
ご連絡:
本件、ご返答頂きました方法でうまくできました。
一連の問い合わせを通じ、取得されるデータに対する比較演算・NULL判定、イベントb竏数の絡ませ方の理解が、随分進みました。ありがとうございます。