🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

Q&A

解決済

3回答

4362閲覧

AccessからSQL Serverのテーブルを更新する際に、実行結果をそのまま取得する方法はありますか?

iromay

総合スコア19

SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

0グッド

0クリップ

投稿2021/03/10 05:27

AccessからSQL Serverのテーブルを更新する際に、実行結果をそのまま取得する方法はあるでしょうか?

現在連番を利用するAccessツールを作成しております。
これまでAccessツールのローカルテーブルで連番を管理していたのですが、
この度、そのAccessツールが複数台にインストールされ、使用されることになりました。
そして、その為にSQL Serverに連番管理用のテーブルを用意し、
各Accessツールからそちらを参照/更新する仕組みとしたいと考えています。

ただ懸念点として、あるAccessツール(仮にAとします。)で
連番テーブルの値を参照し、「003」という結果が得られたとします。
この後Aでカウントアップ処理が4回実施され、
その結果として連番テーブルの値を「007」に更新します。
この時別のAccessツール(仮にBとします。)がAの更新処理前に連番テーブルを参照していた場合、
結果として「003」が複数のテーブルで連番として用いられてしまい、値が重複してしまいます。

Update処理でそのまま結果が取得出来るのならば、
ロックがかかるので上記の様な重複の番号が採番されることを防げるかと思います。
ただ通常のSQL ServerではOUTPUT句を利用してそういった処理が可能なようなのですが、
Accessのパススルークエリを利用して、OUTPUT句を使おうとしても実行出来ないです。

無いかUpdateの直後、他のツールによる参照/編集が行われない状態で
値の取得を行う方法は無いでしょうか?

ご教授いただけますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

あるAccessツール(仮にAとします。)で連番テーブルの値を参照し、「003」という結果が得られたとします。
この後Aでカウントアップ処理が4回実施され、その結果として連番テーブルの値を「007」に更新します。
この時別のAccessツール(仮にBとします。)がAの更新処理前に連番テーブルを参照していた場合、結果として「003」が複数のテーブルで連番として用いられてしまい、値が重複してしまいます。

上記で「Aの更新処理前に連番テーブルを参照していた場合」の部分をロックしないと駄目なケースですね。

このような場合、追加前のテーブルに結果を求めるのには無理があります。

そのテーブルにIDENTITYを設定し、追加後に番号を取得するか、発番用のテーブルを別途準備して、for updateなどでロックした上での管理にするかです。

追記

よく見ると、発番のテーブルで管理はされているのですね。
それで、他の処理で発番済みの値が使用されるなら、単にトランザクションの問題でしょう。
要は、発番したあとに直ぐにコミットせず、その後のデータ処理が行われる迄、コミットしていないという事なのではないでしょうか。

投稿2021/03/10 08:08

編集2021/03/10 09:28
sazi

総合スコア25327

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iromay

2021/03/10 09:47

申し訳ありません。 実はトランザクション、コミットと言った操作をAccess VBAで実施したことが無く、 恥ずかしながら、そもそも存在も名前程度しか知らなかったという有様です。 調べると幾つか試している記事が見つかったので、参考にしながら、試してみたいと思います。
sazi

2021/03/10 09:58 編集

他の回答へのコメントにある > ③印刷完了後、カウントアップされた0003を連番テーブルのラベル名1の発行枚数にUpdateします。 という事ならそういった事象が発生するのは当然で、トランザクションとは無関係です。 >具体的にはUPDATEのタイミングでは排他制御が行われると思うのですが、 UPDATE以前の取得の際に複数が取得すれば、同じ番号になります。 行うなら、先ずはカウントアップして、そのデータを印刷する元データに記録するようにすれば、事象は改善されるはずです。 尚、発番するかどうかは印刷元データに番号が無い場合のみ行う必要があります。
iromay

2021/03/10 15:43

ご回答ありがとうございます。 その場合下記の様な、1台目のPCがUPDATEとその結果を取得する僅かな間に 別のPCがUPDATEを行うという恐れはないでしょうか? 初期状態 連番テーブル: ラベル名   発行枚数 ラベル1    0002 ラベル2    0005 ラベル3    0004 ①PC1のラベル1へのUPDATEで1加算 連番テーブル: ラベル名   発行枚数 ラベル1    0003 ラベル2    0005 ラベル3    0004 ②PC2のラベル1へのUPDATEで1加算 連番テーブル: ラベル名   発行枚数 ラベル1    0004 ラベル2    0005 ラベル3    0004 ③PC1のラベル1の連番の参照で004を取得 ④PC2のラベル1の連番の参照で004を取得 AccessのVBAの中で処理は続けて書いており、また更新内容も単純なものですが、 論理的にUPDATEからのSELECTの間に、間があるのが気になっております。。
iromay

2021/03/11 06:54

sazi様 ご返信ありがとうございます。 ただ、LockEditsは外部のデータベースのロック制御が出来ない様なのです。 今回、接続先がSQL Serverとなり、ODBC接続の為、こちらの利用は難しいのではと思います。
sazi

2021/03/11 07:15 編集

> ただ、LockEditsは外部のデータベースのロック制御が出来ない様なのです。 >外部のデータベース サーバーで使用されるロック機能に対する制御は行いません。 と記載されていますね。 では、トランザクション制御を行い、for updateでロックしてから更新し、コミットですね。 上記の一連の処理は、ストアドで行うようにして、発番の結果を受け取るようにすれば良いでしょう。 以下参考 ストアドプロシージャを実行して戻り値を受け取る方法 https://bayashita.com/p/entry/show/283
sazi

2021/03/11 07:22

> 論理的にUPDATEからのSELECTの間に、間があるのが気になっております。。 自身が発番した結果(Update)をselectで得ようとすれば、ロックしない限り自身の発番の結果でない場合は当然あり得ます。 なので、ロックが必要になります。
guest

0

ベストアンサー

ただ通常のSQL ServerではOUTPUT句を利用してそういった処理が可能なようなのですが、
Accessのパススルークエリを利用して、OUTPUT句を使おうとしても実行出来ないです。

↑これは普通にできますけど…SQLが間違えているとかでは?
実際には直でSQL文を実行するよりストアドプロシージャにラップしたほうが管理が楽です。

またプログラムを変更するならクライアントでテーブルを参照するのではなく
カウントアップした結果を受け取るだけにしてその値を使うようにすればいいと思います。

排他制御もデータベースに任せたほうが楽だと思います。

投稿2021/03/10 08:30

sousuke

総合スコア3830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iromay

2021/03/10 09:51

もしかしたら、Accessのパススルークエリの書き方が良くなかったのかも知れません。 色々と書き方を変えて試してみたのですが、どれも上手くいかずお手上げといった感じでした。。 もし可能であればパススルークエリで実行可能なOUTPUT句を含むUPDATE文について 何かサンプルを頂けないでしょうか? ストアドプロシージャについても、今まで使ったことが無いのですが、調べてみようと思います。
sousuke

2021/03/12 01:53

SQL Server自体はSSMSとかで直接開いたことはありますか? SQL Server Management Studioです。 update A set テスト=テスト output inserted.テスト as iテスト,deleted.テスト as dテスト from dbo.テストテーブル as A こんな感じで実行できると思います。 パススルークエリをする前にまずはデータベースで直接実行できるかを 確認したほうがいいと思います。SSMSは構文エラーとかも教えてくれます。
guest

0

マルチユーザーでの連番処理は、連番を取得すると同時に+1して更新しておくのが通常のやり方かと。
その間は他のユーザーは更新できないように排他的ロックしておく。(ロックする時間は最小限になるように)

連番テーブルを参照/更新を試みたときに、ロックされていて失敗したら時間を置いて再参照するようにします。


現状は、
ユーザーAが新規レコードの入力を始めると同時に、連番テーブルから連番を取得する。
入力後、保存する、同時に連番テーブルの連番も更新する。
という方法になっているのだと推測します。

この方法で行くなら、ユーザーAが入力中は連番テーブルは排他ロックして更新できないようにする必要があります。しかし、それではマルチユーザーで共有している場合はだれかが入力中は他ユーザーは入力できません。これは使い勝手が悪いです。

上記の回答の方法は、
ユーザーAが新規レコードの入力を始めると同時に、
連番テーブルから連番を取得し、連番に+1してすぐに保存する。
他のフィールドを入力後保存する。
です。この方法なら重複することはないですが、入力途中でキャンセルした場合は、連番に抜けができます。

連番に抜けがでないようにするなら、
新規レコードの入力を始めるときは連番は取得せずに、
入力後保存するときに、連番取得、+1して更新とします。

この3つの方法からの選択になります。

投稿2021/03/10 06:36

編集2021/03/10 08:33
hatena19

総合スコア34073

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iromay

2021/03/10 09:43

早速のご返事ありがとうございました。 言葉足らずで申し訳ありません。 具体的なイメージとしては何種類かラベルが存在し、 そのラベル毎に連番を管理しています。 連番テーブル: ラベル名   発行枚数 ラベル1    0002 ラベル2    0005 ラベル3    0004 この時端末も複数台(PC1、PC2)存在しており、 Accessで作成したラベルツールから上記ラベル連番テーブルへアクセスします。 今ラベルツールで想定している流れとしては ①連番テーブルから、出力するラベルの発行枚数を取得  (仮にラベル1を発行する場合は0002を取得) ②印刷を実行。この時Accessのレポートで作成するラベルに  連番項目として取得した0002を1つカウントアップして0003として印字します。 ③印刷完了後、カウントアップされた0003を連番テーブルのラベル名1の発行枚数にUpdateします。 実際に同じ種類のラベルを同時に長い時間出すことは少ないので排他ロックによる待ち時間は 今回あまり気にしなくても良いと考えています。 ただ実はAccess VBAについてあまり長けておらず、 肝心の対象テーブルの排他制御(更新も参照も不可)の方法が分からないのです。 具体的にはUPDATEのタイミングでは排他制御が行われると思うのですが、 UPDATEの後に参照する為に、SELECTを実行するとして、 その間に他のクエリが実行されていないようにする方法が分からないという状況になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問