いつも参考にさせて頂いています。ありがとうございます。
しばらく悩んでいるのですが解決できず、皆様のお知恵をお借りしたいと思います。
Table名 CUST
Field名 CODE: String[6]
NAME: String[20]
BD: String[10] (誕生日を西暦で文字型にしている)
SUB1: Integer
TQueryを使い、計算項目(YEARS)を追加し、OnCalcFieldsで現在の年齢を計算しています。(ここまでは何の問題もない)
次に、年齢別の該当者数を出したいのですが。。。。。
<例>
YEARS COUNT(*)
20 111
21 222
TQueryの計算項目ではSQL文にGroup Byが使えない。
計算項目(YEARS)をSUB1に書き込むことはできるのでしょうか。
While not Query1.Eof do で1行ずつ見るには時間がかかり過ぎます。
何か良い方法はないでしょうか。よろしくお願いします。
年齢別の該当者数を出す前にCUSTの年齢(SUB1)を一括更新する処理を追加すれば良いのでは?
年齢の一括更新をした後に年齢計算の基準となる日付(例えば今日の日付)をデータベースやレジストリなどに記録するようにしておいて、同じ日付であれば年齢の一括更新をしないようにすれば効率的だと思います。(もちろん、CUSTに新しいデータを追加した場合や生年月日が変更された場合は、年齢の一括更新をするように考慮しないといけませんが...)
masayan さん早速ありがとうございます。
SQL文の問題かと思うのですが、一括更新の方法が?です。
UPDATE CUST SET SUB1= ????? です。
年齢計算には、独自のFunctionを作って計算していますが、SQL文に埋め込むことはできないし。どのようにすればよろしいのでしょうか?ご指導頂けないでしょうか?
>SQL文の問題かと思うのですが、一括更新の方法が?です。
失礼しました。SQLでは無理のような気がします。
TTableは使えないのでしょうか?
TTableであれば年齢が変わる人のみ更新といった制御が可能になるので処理を速くできるかもしれません。
例えば...
Table1.Open;
while not Table1.Eof do
begin
BD := Table1.FieldByName('BD').AsString;
n := xxxxx(BD); {<= 生年月日から年齢を取得する関数}
{ 年齢が変わっているか? }
if Table1.FieldByName('SUB1').AsInteger <> n then
begin
{ 変わっている場合だけレコードを更新 }
Table1.Edit;
Table1.FieldByName('SUB1').AsInteger := n;
Table1.Post;
end;
Table1.Next;
end;
Table1.Close;
といった感じです。
masayanさんありがとうございます。
これから実験してみます。
何のデータベースを使っているのかわかりませんが、年齢を出すQueryをサブクエリーにして、それから人数を出せば簡単と思います。
HOotaさんありがとうございます。
データベースは、最終的にはInterBaseにする予定ですが、現在DBFで実験をしています。
年齢を出すQueryはどのように記述するのでしょうか?
SQL関係の本を読み漁っているのですが、まだ良くわかりません。勉強不足ですみません。
InterBaseは知らないので、
SLELCT
今日の日付を出す関数 - 文字を日付に直す関数(BD) as 年齢
COUNT(*)
FROM テーブル
でどうでしょうか?
HOotaさんありがとうございます。
生年月日にはNULLも存在します。閏年もあるし。もう少しじっくり考えて見ます。
閏年は、Interbaseが計算してくれます。Nullに対しては何らかの日付を入れるか、計算しないようにすればいいのでは
話の流れとちがいますが、先ず最初の
>While not Query1.Eof do で1行ずつ見るには時間がかかり過ぎます。
が問題では?
DBFファイルならインデックスを適切に作成していれば10万件単位のデータでも
ストレス無く処理できるはずです。
>最終的にはInterBase...
数年前はInterBaseはユーザ定義関数を設定できました。また、InterBaseであればHOotaさんの言われるようにSQLで年齢の計算はできると思います。
ユーザ定義関数を定義する場合は、将来DBを変更する場合は面倒になりそうです。また、年齢計算を都度更新する場合は、複数のクライアントから更新SQLが実行されたり..等のパフォーマンス低下に対する管理処理が面倒です。
当然それぞれ一長一短になるで検討が必要ですね。
InterBaseで関数(ユーザー定義・外部)を使用したとしても
それをGROUP BY句に使用することは出来ませんので
年齢を計算する関数を作ったとしても
年齢別の件数を調べることは出来ませんので、
結局は1レコード毎に処理することになります。
どうしてもデータベース側で処理させたければ
ストアドプロシージャを作るほうが早いです。
>GROUP BY句に使用することは出来ません..
えびさん、ご指摘ありがとうございます。GROUP BY句使えませんか...
現在、テストする環境がないので何とも言えませんが、それをサブクエリーにもできないのでしょうか?GROUP BYも使えず、サブクエリーもできなかったら返答になりませんね、すみません。
サブクエリーは基本的にWHERE句でカラムとの比較に使うもの
だと思いますので今回のようなケースでは使えないと思います。
アクセス等ならSELECT句のネストが出来ますので
(今環境が無いので断言できませんがオラクルとかも出来たような)
CUSTテーブルから年齢計算した結果をさらに年齢でグループすれば
期待する結果が得られます。
ツイート | ![]() |