Mtbl_所属歴というテーブルに、社員No、社員名、開始日、終了日、所属が入っています。
1.開始日の最小値と終了日の最大値以外の所属を抽出し、
2.特定の名称(育児、介護の文字が含まれる)が含まれる場合を削除したいと思っています。
第一段階として、このようなサブクエリを作ったのですが、結果は取れるのですがパフォーマンスが悪すぎてまともに動きません。
SELECT T1.FROM [Mtbl_所属歴] AS T1
WHERE
Exists (select from [Mtbl_所属歴] AS T2 where T1.社員No = T2.社員No and T1.開始日 > T2.開始日)
and
Exists (select * from [Mtbl_所属歴] AS T2 where T1.社員No = T2.社員No and T1.終了日 < T2.終了日)
当初はこのように書いていたのですが、結果が取れず、上記のように修正したのですが、
この書き方ではどうして取れないのでしょうか、この点も理解できておりません。
SELECT T1.FROM [Mtbl_所属歴] AS T1
WHERE
Exists (select from [Mtbl_所属歴] AS T2 where T1.社員No = T2.社員No and T1.開始日 > T2.開始日 and T1.終了日 < T2.終了日)
よろしくお願いします。
[社員No]の値が同一であるグループごとに、ということでしょうか。
EXISTSを使った相関サブクエリは、基本的に遅いです。
相関(サブクエリからメインを参照する)を利用しない方法を検討しましょう。
下記でどうでしょう。
これでもまだ遅いなら、
社員No、開始日、終了日 にインデックスを設定してください。
意味があるのかしら?例えば、年度毎に保管期間5年間して過ぎたら削除する、みたいな感じじゃダメなの?
Accessは( Microsoft謹製のDBMSでは )
相関サブクエリのパフォーマンスがJOINに比べて劣る印象はありますね
しかしながら、Access-SQLにおいて
という場合、
つまり、UPDATE文やDELETE文を発行するケースでは
FROM句やJOIN句に sum, max, min といった集計関数を含めることは出来ません
( 利用できるのは、パフォーマンスが悪いD系の定義域集計関数だけ )
そのため、hatenaさんのアドバイスにあるとおり適切にINDEXを設定した上で
以下のようなSQLを発行するといいでしょう
結果セットとパフォーマンスが確認できたら
SELECT → DELETE に変更し
の条件も付与して下さい
なお、上記の相関サブクエリでも
という場合は
hatenaさんの回答>> 2のサブクエリ Q1 の結果セットを
一旦テンポラリテーブルに格納するといいでしょう
ご回答ありがとうございます。
EXISTSを使った相関サブクエリはJOINに比べて劣るのですね。勉強になります。
履歴データなので基本的には消せないのですが、
ワークテーブルを使って削除するか、もしくはフラグを立てて読み飛ばすかということを
したいなと。いずれにしても更新を想定しています。
となると、インデックスを貼ってEXISTSですか。まずは試してみます。
開始、終了日の条件はHAVINGになるのですね。勉強になりました。
それでも重いようであれば、この方法を採用してみます。
>hatenaさんの回答>> 2のサブクエリ Q1 の結果セットを
>一旦テンポラリテーブルに格納するといいでしょう
SQLをゴリゴリ書スキルがなく、更新不可となってしまうクエリを一時テーブルに書き出して、
Delete、Updateなどを行うとかはよく使っていました。
データベースなので履歴データは基本は削除しない運用が望ましいですね。
ワークテーブルを使うのなら、上記の集計クエリを含むクエリを追加クエリにして追加すればすみます。
フラグフィールドを追加してそれを更新するなら、EXISTSサブクエリを使用した更新クエリにすることになりますが、
自分がするなら、前回の質問でも回答しましたが、VBAでレコードセットを回して更新する方法をとります。
SQLでいくか、VBAでいくかは、得意不得意があると思いますので、好みでいいと思います。
SQLで大分改善はしました。が、ちょっと待ち時間がストレスに感じるくらいです。
hatenaさまにいただいた、DAOでループ処理する方法でゆきたいと思います。
コードを一見して動きは理解できました。
rs.MovePreviousで1レコード前に戻るというのもできるのですね。
考えつきもしませんでした、勉強になりました。