プログラム初心者です。
オラクル(11g)で、10個のPCで10人が、あるテーブルのデータを更新していく、システムを作成(VB2005)しています。
画面は2パターンです。
・データ一覧表示画面
・上記からデータを選択し、編集する用の画面
例として下記のようなデータがあります。
テーブルC 日付順 番号はユニーク
日付_番号_ステータス__レコードカウント(Rc)
1/3____1_____Q________0
1/5____2_____R________1
1/6____5_____G________2 (Rc=2)
1/7____7_____P________3 (Rc=3)
1/20__ 9_____R________4
2/1___10_____U________5
動作の流れ
1.まず、この全データをSQLで読込みます。
SELECT * FROM テーブルC ORDER BY 日付 ASC
これが一覧表示画面(VB2005のグリッドビュー等)に表示されます。
2.A氏が例えば1/6のレコードを編集したいとします。
そこで、1/6(日付)の列をマウスで選択。このとき列番号(レコードカウント)は2になります。
編集画面フォームに、同じSQL(SELECT * FROM テーブルC ORDER BY 日付 ASC)
と、列番号(レコードカウント)2を、引渡しします。
3.編集画面で、引き渡されたSQLを実行し、そのデータを全てDatatblに格納します。
そのデータの3つめ(レコードカウント2)を参照します。
datatabl.Rows(2).Item("ステータス")
データは参照後、ある条件によりステータスが変わります。
ステータスが、"Z"になった場合、そのレコードは、テーブルAに移動されます。
4.編集後は、他のテーブルに移動する場合でも、テーブルCがそのまま更新される場合でも、
自動的に次の列のレコードに移行し編集を行う。
今回は例として、1/6のレコードのステータスが"Z"になって
A氏は次に1/7(Rc3)のデータを編集作業に入ります。
5. 4.を実行するため、また同じSQLを実行。
SQL実行後、レコードカウントを次に移行すればいいのですが(Rc=2に1を加え、Rc=3とする)、
Rc=3を見ても、1/20のデータが抽出されて しまいます。 (1/6のレコードが移動してなくなってしまった場合)
また、他の例として、上記と同様に、A氏が1/6のデータを編集中に、他の人が1/3,1/5のデータを編集移動
してしまった場合、レコードカウントがぐちゃぐちゃになってしまいます。
こうした多くの人がデータを編集、更新・移動する場合のテーブルを、日付順に作業させていく場合は、どのような制御
(またはオラクルの機能)をすれば、可能なのかご指導頂ければ助かります。
No.5ベストアンサー
- 回答日時:
とりあえず、なんとかなったようでよかったです。
新しく質問立てて頂いていいかと思います。
(なにぶん、今は仕事ではOracleを使っていませんので、細かいところをすぐ試すわけにはいかないです。もっと早く回答できる人もいるでしょう)
ちなみに、文字列の大小はコードで比較されますが、ASCIIでもUNICODEでも'8'<'A'だと思いますよ。
番号がVARCHAR2で常に10桁(10文字)入っているなら、TO_CHARを使わずにそのまま結合してはだめだったのかな、と思いました。
なるほど、オラクルで、文字コード加味してくれ、そのままいけるのであれば、とても楽です。
そちらも試してみますね。
本当にありがとうございました!
No.4
- 回答日時:
クエリはOracleが手元にない状態で書いたものだったので、ちょっとひやっとしましたが、構文としては正しかったようです。
念のため、11gで確認しましたので、実テーブルに即した内容に書き換えたものを。。SELECT * FROM T_JOB
WHERE (TO_CHAR(DAY,'yyyyMMdd') || NO) IN
(SELECT MIN(TO_CHAR(DAY,'yyyyMMdd') || NO) FROM T_JOB
WHERE (TO_CHAR(DAY,'yyyyMMdd') || NO)>
(SELECT TO_CHAR(DAY,'yyyyMMdd') || NO FROM T_JOB WHERE NO='<oldNo>'))
日付も一緒にパラメータにできるようなので、以下の方がわかりやすければ。。
1) SELECT * FROM T_JOB
WHERE (TO_CHAR(DAY,'yyyyMMdd') || NO) IN
(SELECT MIN(TO_CHAR(DAY,'yyyyMMdd') || NO) FROM T_JOB
WHERE (TO_CHAR(DAY,'yyyyMMdd') || NO)>'<yyyyMMdd+No>')
2) SELECT * FROM
(SELECT DAY,NO FROM T_JOB
WHERE (TO_CHAR(DAY,'yyyyMMdd') || NO)>'<yyyyMMdd+No>'
ORDER BY DAY,NO)
WHERE ROWNUM=1
ちなみに、クエリの解釈は書かれた内容であっていますよ。
ありがとうございます。上記参考に動作しました!
他、24時間対応を調べて、値10桁対応(90と110では 90が優先されてしまっていた)も直して下記で一度完成形です。とても勉強になりました。
SELECT * FROM T_JOB WHERE (TO_CHAR(DAY,'YYYYMMDDHH24MISS') || TO_CHAR(NO,'9999999999'))
IN (SELECT MIN(TO_CHAR(DAY,'YYYYMMDDHH24MISS') || TO_CHAR(NO,'9999999999'))
FROM T_JOB WHERE (TO_CHAR(DAY,'YYYYMMDDHH24MISS') || TO_CHAR(NO,'9999999999'))
>
(SELECT TO_CHAR(DAY,'YYYYMMDDHH24MISS') || TO_CHAR(NO,'9999999999')
FROM T_JOB WHERE NO = '" & Noold & "'))
ここでまた新仕様がでてきて、番号(定義は文字列です)の頭(10桁目固定)が、
8の場合、8
9の場合、9
Aの場合、10
Bの場合、11
~~
Yの場合、29
と、認識してほしいという要望がでてしまいました・・・。
8000000002
A000000001
だったら、A000000001を大きい番号で判断したいということですね。(DATABASEは変更してはいけません)
これにより、少々文が長くなってきたので、この辺はVBの変数を使い解析しやすくしたいと思ってます。
これについては大変助かりましたので、また質問を新しく立てたいと思いますが如何でしょうか。
ありがとうございました。
No.3
- 回答日時:
そうですか。
ユニークなのは番号だけでしたか。それであれば、本来は番号だけをキーにし、番号順に処理することにして、次の番号を検索しにいくのがシンプルですが、拝見する限りは日付順に処理したそうですね。
であれば、日付+番号順に処理することとし、次のレコードは
(1)日付が同じで番号が前回編集番号より大きいか、日付が前回編集番号のレコードの日付よりも大きいものを日付・番号順で取り出してROWNUM=1で1件だけ取る
(2)SELECT 番号 FROM テーブルC
WHERE (TO_CHAR([日付],'yyyyMMdd') || [番号]) IN
(select MIN((TO_CHAR([日付],'yyyyMMdd') || [番号])) FROM テーブルC
WHERE (TO_CHAR([日付],'yyyyMMdd') || [番号])
> (SELECT (TO_CHAR([日付],'yyyyMMdd') || [番号]) FROM テーブルC WHERE [番号]=前回編集した番号))
などの方法になるでしょう。
排他制御の仕組みは1つ入れればいいと思います。DBの質問なのにアプリケーションロックをすすめるのもどうかとは思いましたが、DBロックにする場合は慎重に検討してください。
この回答への補足
SQL実行してみましたが、勉強不足で構文がうまくできないようです・・・。
とりあえず大きく3つに分けられるとおもいます。
1
SELECT * FROM T_JOB WHERE (TO_CHAR([日付],'yyyyMMdd') || NO)
2
SELECT MIN(TO_CHAR(DAY,'yyyyMMdd') || NO) FROM T_JOB WHERE (TO_CHAR(DAY,'yyyyMMdd') || NO)
3
SELECT (TO_CHAR(DAY,'yyyyMMdd') || NO) FROM T_JOB WHERE NO = '" & NOold & "'"
3だけは通りました。1,2がどこか違うようです。
大きい分け方も違うんでしょうね・・・。WHERE部分の連結がよくわかってないかもしれません。
ちなみに、NO:番号 DAY:日付で、最終的には、テーブルの全てを抽出したいです。(なので頭はSELECT *です。)
初心者な自分にはなかなか高度なSQLで、解析に時間がかかりました・・・。頑張って解析しました。
(2)のケースですが、これは、(1)と同じことをしているのでしょうか?
要するに、 日付と番号を連結して大小比較実現した感じでしょうか。
例
日付________番号
2008/01/01__0034 ・・・I
2008/01/01__0036 ・・・II
2008/01/01__0035 ・・・III
これを||で一つの数字に連結 (日付も数字に変換して、日付番号ともに、大小比較できるようにしている)
200801010034
200801010036
200801010035
比較の二つ両方を連結し、結論としては、上記SQLで
200801010035(MINで抽出されたもの) > 2008010100034(前回更新したもの)
↑これが実行されるかんじで、
Iの次にはIIIが抽出されるという感じになるのでしょうか?
No.2
- 回答日時:
悲観的ですか。
。アプローチを2つ紹介しますので、ニーズに合う方を考えてみてください。1)データベースによるロック
トランザクションモードでSELECT文に FOR UPDATE NOWAIT句をつければ、更新ロックがかけられ、そのレコードは解放(COMMIT/ROLLBACK)されるまでは他の人が更新することはできなくなります。すでに他の人が更新ロックを取得していれば、エラーになります。
・選択したデータに対しては確実に他の人の更新を阻止できます。
・他人の状況は刻々と変わりますので、選択できるかどうかはSELECT FOR UPDATEの結果を見ないとわかりません。
・更新してもしなくても確実に解放するようにします
・誰かがデータを選択したまま放置した場合、そのデータはずーっと誰も更新できない状態になります。
2)アプリケーションによるロック
データに更新者を収録するフィールドを設け、選択した場合はこのフィールドをまず更新しにいく方法です。更新できればデータ編集の権利を得たことになります。
・一覧を読み込んだ時点で今誰が作業中かを表示させられます。
一覧更新ボタンをつけるなど割り切れば、読み込んだときに作業中のものはDBをつつかなくても「選択不可」とできます。
・次に編集するレコードを取得するのがDBロックよりも簡単です。
・まず一度更新しにいくので、手間がかかります。またうまくやらないと不整合(編集していないのに編集中)が生じるリスクはあります。
・更新してもしなくても、編集終了時には更新者をクリアする必要があります。
ありがとうございます!
とてもわかりやすい解説助かります!
ちなみに、上記はどちらか片方でよいものなのでしょうか?(両方まではやる必要なし?!)
日付で一番近いものを順に抽出するように、以下のようにSQLを組み替えました。
SELECT 番号 FROM テーブルC WHERE 日付
IN ( SELECT MIN(日付) FROM テーブルC WHERE 日付 >= 前回編集した日付 )
主キーは番号です。
日付 番号
2008/1/1 07
2008/1/5 09
2008/1/5 04
2008/1/5 03
2008/1/5 05
この場合更新後、次のデータに行った場合、番号09の後に、また09を抽出してしまいます。
番号09の値を二度抽出しないようにするには、番号の値を保持しておかなければ行けないでしょうか?なにか他の方法がありましたらご教授お願いしたいです。
No.1
- 回答日時:
全部はコメントしきれませんが、毎回読み込むたびに変わる可能性のあるもの(=Rc)をパラメータとして渡そうとしているところをまず改めてみてはどうでしょうか。
「番号はユニーク」と書いてありますし、日付もユニークならば、番号または日付をパラメータにすべきです。編集を行う行が特定されれば、編集画面ではそのデータだけを読み込めばいいわけです。
更新後の次の行を自動的に割り出したければ、その時点で存在する次の日付のデータの番号を求めて、その番号のものを読み込めばよいです。
SELECT 番号 FROM テーブルC
WHERE 日付 IN
(SELECT MIN(日付) FROM テーブルC
WHERE 日付>[今編集した日付])
なお、今回の情報だけではどこまでロックを掛けたいのか判断できませんでした。一覧に読み込んだものが選択できることを保証するのか、選択したものを更新できることを保証するのか、更新の競合も許すのかで対応は変わってくるはずです。
ありがとうございます。大変勉強になりました。
その方法、SQLで試してみようと思います。
また、ロックもいまいち不明部分があるのですが、現状のやりたいことは、
一覧画面では、他の人が開いているレコードは、選択できないようにする。
編集画面でも、他の人が開いているレコードは、更新できないようにする。
ただ一覧画面で、A氏B氏が同時に、同レコードを選択した場合、編集画面にいってしまう気がします。
その際、編集画面での更新は早いもの勝ちというようにしたいです。(後の人は更新不可能)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(データベース) IT用語について質問です。 以前ITパスポートの試験を受けた際にデータベースが何の集まりかについての 2 2022/12/10 12:29
- Visual Basic(VBA) access count数を変数に格納 2 2022/03/30 19:21
- その他(データベース) 更新クエリをリンクデータベーステーブルに実行し実行時エラー3362固有インデックスに重複する値が含ま 1 2022/09/21 11:44
- PHP クエリObjectをforeachで回す時に、次のレコードへ移動せずに次のレコードを取得したい 2 2022/07/28 15:29
- Oracle 下記のsqlで取得されるレコード以外を取得する方法ありますでしょうか。 SELECT B.番号, B 2 2022/04/20 23:21
- Access(アクセス) Access IF文でテーブルに存在しない場合の処理について 2 2022/10/10 18:09
- Excel(エクセル) エクセルで沢山のレコードの最後に追記するには? 7 2023/04/10 13:27
- Excel(エクセル) countif関数について質問 4 2022/06/14 12:11
- Access(アクセス) アクセス where句を使用して複数条件抽出をするには 2 2022/08/29 13:24
- Ruby pandasでsqlite3にテーブル作成・追加・読み出しでindexの取り扱い方教えてください 5 2023/03/08 09:57
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
SQLサーバで和暦から西暦に変換...
-
今日の日付が入った行のデータ...
-
特定の日付が第何週目にあるか...
-
Accessの数値から時間に変換す...
-
14桁の日付(YYYYMMDDHHMMSS)を...
-
エクセル 日付による並べ替え...
-
テーブルの主キーをdate型...
-
Excelの並び替え(先頭の文字以...
-
ExcelのSUMPRODUCTで日付の範囲...
-
エクセルVBA 今日の日付行...
-
日付書式に変換でこまっています!
-
日付の切り出し方法について
-
SQLで今日の日付でWhereしたい
-
SQLite3のtext→date変換について
-
excel 日付のみ置換したいのです
-
重複するIDのデータを1行にま...
-
DB2のSQL(日付)について
-
Oracle11gのDATE型
-
23時59分59秒までのデータを抽...
-
SQLで部分的にGROUP BYしたいとき
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Accessの数値から時間に変換す...
-
今日の日付が入った行のデータ...
-
エクセル 日付による並べ替え...
-
SQLサーバで和暦から西暦に変換...
-
SQLで部分的にGROUP BYしたいとき
-
14桁の日付(YYYYMMDDHHMMSS)を...
-
ExcelのSUMPRODUCTで日付の範囲...
-
テーブルの主キーをdate型...
-
Excelグラフの日付軸の日付がず...
-
oracle 文字列 01:45 を時間に...
-
23時59分59秒までのデータを抽...
-
SQL スクリプトのご相談
-
WHERE句にて「30日前から今日ま...
-
指定した年月までのデータを取...
-
DB2のSQL(日付)について
-
yyyy/M/dをyyyy/MM/ddに変換
-
重複するIDのデータを1行にま...
-
日付型なら変数の先頭になん...
-
日付書式に変換でこまっています!
-
Excelの並び替え(先頭の文字以...
おすすめ情報