Access VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


1226 / 2272 ツリー ←次へ | 前へ→

【8127】レコード削除 Satsuki 06/7/3(月) 13:53 質問[未読]
【8137】Re:レコード削除 小僧 06/7/3(月) 16:52 発言[未読]
【8148】Re:レコード削除 855 06/7/3(月) 18:16 発言[未読]
【8150】Re:レコード削除 小僧 06/7/4(火) 10:01 発言[未読]
【8155】Re:レコード削除 Satsuki 06/7/4(火) 10:59 お礼[未読]
【8157】Re:レコード削除 Satsuki 06/7/4(火) 11:27 お礼[未読]
【8154】Re:レコード削除 Satsuki 06/7/4(火) 10:29 質問[未読]
【8159】Re:レコード削除 小僧 06/7/4(火) 11:47 回答[未読]
【8161】Re:レコード削除 855 06/7/4(火) 16:07 発言[未読]
【8163】Re:レコード削除 Satsuki 06/7/4(火) 17:10 お礼[未読]
【8162】Re:レコード削除 Satsuki 06/7/4(火) 17:06 お礼[未読]
【8165】Re:レコード削除 小僧 06/7/4(火) 17:24 回答[未読]
【8167】Re:レコード削除 Satsuki 06/7/4(火) 17:54 お礼[未読]

【8127】レコード削除
質問  Satsuki  - 06/7/3(月) 13:53 -

引用なし
パスワード
   こんにちは。Satsukiと申します。
かなりおかしい所があると思われますが、どこを調べてもわかりません。どなたかご教示よろしくお願いいたします。

「データ」テーブルと「位置」テーブルのすべての値を計算し、「距離」ワークテーブルに追加していくのですが、1件目のデータテーブルの値とすべての位置テーブルの値が計算し終わったところで、「距離」ワークテーブルの「KyoriX」フイールドの上位5位を「TOP5」に入れ、もとの「距離」ワークテーブルのレコードをすべて消すという動作を繰り返したいのですが、
rs3.Deleteのところで
「キー列の情報が足りないか、正しくありません。更新の影響を受ける行が多すぎます」とでます。
ちなみにrs3(距離)テーブルは、一巡めで4472件になります。
また、上位5件のはずが、「TOP5」テーブルには3件までしか追加されていません。また位置テーブルは全部で4512件で、「距離」テーブルは40件ほど足りません。
「データ」テーブルは1572件あります。

Public Sub keisan()
Dim cn As ADODB.Connection
Dim rs1 As ADODB.Recordset
Dim rs2 As ADODB.Recordset
Dim rs3 As ADODB.Recordset
Dim rs4 As ADODB.Recordset

Set cn = CurrentProject.Connection
Set rs1 = New ADODB.Recordset
Set rs2 = New ADODB.Recordset
Set rs3 = New ADODB.Recordset
Set rs4 = New ADODB.Recordset

rs1.Open "データ", cn, adOpenStatic, adLockReadOnly
rs2.Open "位置", cn, adOpenStatic, adLockReadOnly
rs3.Open "距離", cn, adOpenKeyset, adLockOptimistic
rs4.Open "TOP5", cn, adOpenKeyset, adLockOptimistic

rs1.MoveFirst

Do Until rs1.EOF
  rs2.MoveFirst
  Do Until rs2.EOF
    rs3.AddNew
      rs3![kyotenmei] = rs2![拠点名]
      rs3![kyoriX] = rs2![X1] - rs1![X]
      rs3![kyoriY] = rs2![Y1] - rs1![Y]
    rs3.Update
  rs2.MoveNext
  Loop

  rs3.Close
  rs3.CursorLocation = adUseClient
  rs3.Open "距離", cn, adOpenKeyset, adLockOptimistic
  rs3.Sort = "kyoriX DESC"
  i = 0
  For i = 1 to 5
    rs4.AddNew
      rs4![kyotenmei] = rs3![kyotenmei]
      rs4![kyoriX] = rs3![kyoriX]
      rs4![kyoriY] = rs3![kyoriY]
      i = i + 1
    rs4.Update
  Next i

  Do Until rs3.EOF
    rs3.Delete
    rs3.MoveNext
  Loop

  rs3.Close

rs1.MoveNext
Loop


rs1.Close
rs2.Close
rs3.Close

cn.Close

End Sub

【8137】Re:レコード削除
発言  小僧  - 06/7/3(月) 16:52 -

引用なし
パスワード
   ▼Satsuki さん:
こんにちは。

やりたい事がちょっと複雑なので
一つ一つ整理して行きましょうね。

> また上位5件のはずが、TOP5 テーブルには3件までしか追加されていません。

>  For i = 1 to 5
>  
>    i = i + 1
>  
>  Next i

i の値が途中でカウントアップされてしまっている為、
この場合は「1」「3」「5」しか処理されませんよね。

あとご提示のコードですと rs1 が 2レコード目になった際、
rs3 が Close したままになっているためそこでエラーが返って来てしまいますね。


ロジックで疑問なのですが、

> 「距離」ワークテーブルの「KyoriX」フイールドの上位5位

を出したいという事なのですが、

> rs3![kyoriX] = rs2![X1] - rs1![X]

しか処理をしていないという事は
実質「位置」テーブルの「X1」フィールドの上位5位と
変わりがないのではないでしょうか。

もしそうであるならばもう少し簡単に上位5位が取って来れそうですね。

【8148】Re:レコード削除
発言  855  - 06/7/3(月) 18:16 -

引用なし
パスワード
   こんにちは、まず小僧さんが言われたようにFor文の中のI = I + 1はいらないですね。
あと↓これも修正必要ですね。
>ご提示のコードですと rs1 が 2レコード目になった際、
>rs3 が Close したままになっているためそこでエラーが返って来てしまいますね。

小僧さんが言われた、
> ロジックで疑問なのですが、
> > 「距離」ワークテーブルの「KyoriX」フイールドの上位5位
> を出したいという事なのですが、
> > rs3![kyoriX] = rs2![X1] - rs1![X]
> しか処理をしていないという事は
> 実質「位置」テーブルの「X1」フィールドの上位5位と
> 変わりがないのではないでしょうか。
> もしそうであるならばもう少し簡単に上位5位が取って来れそうですね。

では、

>Do Until rs2.EOF
>  rs3.AddNew
>  rs3![kyotenmei] = rs2![拠点名]
>  rs3![kyoriX] = rs2![X1] - rs1![x]
>  rs3![kyoriY] = rs2![Y1] - rs1![y]
>  rs3.Update
>  rs2.MoveNext
>Loop

位置テーブルのrs2![X1]がrs2.MoveNextで値が変わるので、
単純に「X1」フィールドの上位5位では無理そうですね。


以下気になった点、、


>rs3.Close
>rs3.CursorLocation = adUseClient
>rs3.Open "距離", cn, adOpenKeyset, adLockOptimistic
わざわざrs3をClose・Openさせなくてもいい気がします。(何のエラーにもなりませんけど。)

>rs3.Sort = "kyoriX DESC"
のあとに rs3.MoveFirst が必要かも。?

>I = 0
>For I = 1 To 5
>  rs4.AddNew
>    rs4![kyotenmei] = rs3![kyotenmei]
>    rs4![kyoriX] = rs3![kyoriX]
>    rs4![kyoriY] = rs3![kyoriY]
>    I = I + 1
>  rs4.Update
>Next I

I = 0 はいらないですね。
I = I + 1 も省いて。
このFor文にrs3のMoveNextがないので同じ値しか書き込みにいってないです。

>Do Until rs3.EOF
>  rs3.Delete
>  rs3.MoveNext
>Loop

この処理に入る前にrs3のMoveFirstが必要です。

色々書きましたけど、Delete時のエラー解決にはなってないと思います。。
実際に動かさずに書いた文章なので間違いがあったらすいません。

【8150】Re:レコード削除
発言  小僧  - 06/7/4(火) 10:01 -

引用なし
パスワード
   ▼Satsuki さんm855 さん:
おはようございます。

>位置テーブルのrs2![X1]がrs2.MoveNextで値が変わるので、
>単純に「X1」フィールドの上位5位では無理そうですね。

[データ]
ID    場所             X    Y
1    東京ディズニーランド    35.63    139.88
2    関西空港          34.43    135.25


[位置]
拠点名       X1     Y1
栃木県宇都宮市   36.33    139.53
群馬県前橋市    36.23    139.03
茨城県水戸市    36.22    140.28
埼玉県浦和市    35.51    139.38
東京都中央区    35.41    139.45
千葉県千葉市    35.36    140.06
神奈川県横浜市   35.26    139.38


の様なダミーデータを使って実験をしていたのですが、

>  Do Until rs2.EOF
>  rs3.AddNew
>  rs3![kyotenmei] = rs2![拠点名]
>  rs3![kyoriX] = rs2![X1] - rs1![x]
>  rs3![kyoriY] = rs2![Y1] - rs1![y]
>  rs3.Update
>  rs2.MoveNext
>  Loop

でしたら

X 35.63 が固定で
X1 が 36.33、36.23、…の様に変化するだけなので、
距離テーブルに入る上位5位は、
そのまま位置テーブルの上位5位になってしまうのかな、と。

これは Satsuki さんの仕様によるものなのでしょうけど、
もし X、Y にあたるものが緯度経度の様なものでしたら、
2地点の緯度経度から計算される距離のTop5を求めなければいけないのかな
と思った次第です。

(X、Yというフィールド名から緯度経度を想像しただけですので
まったくの勘違いでしたらすみません)

【8154】Re:レコード削除
質問  Satsuki  - 06/7/4(火) 10:29 -

引用なし
パスワード
   小僧さん、おはようございます。
早速のお教示ありがとうございます。

>やりたい事がちょっと複雑なので
>一つ一つ整理して行きましょうね。

はい、どうぞよろしくお願いいたします。

>i の値が途中でカウントアップされてしまっている為、
>この場合は「1」「3」「5」しか処理されませんよね。

ほんとですね。とても初歩的な間違いでした。初心者とはいえ、お恥ずかしい限りです。

>あとご提示のコードですと rs1 が 2レコード目になった際、
>rs3 が Close したままになっているためそこでエラーが返って来てしまいますね。

rs1.MoveNext の前の rs3.Close を削除しないといけないのですね。

>ロジックで疑問なのですが、
>> 「距離」ワークテーブルの「KyoriX」フイールドの上位5位
>を出したいという事なのですが、
>
>> rs3![kyoriX] = rs2![X1] - rs1![X]
>
>しか処理をしていないという事は
>実質「位置」テーブルの「X1」フィールドの上位5位と
>変わりがないのではないでしょうか。
>
>もしそうであるならばもう少し簡単に上位5位が取って来れそうですね。

説明不足で申し訳ありません。といいますか、ここは本当はもう少し複雑な式がくるのですが、少数点以下をまったく計算してくれないので、あとで改めてお伺いしようと思い、とりあえず簡単な式を入れておきました。

TOP5のテーブルには5件入るようになりました。引き続きご指導お願いいたします。(現在も同じエラー内容です。)

【8155】Re:レコード削除
お礼  Satsuki  - 06/7/4(火) 10:59 -

引用なし
パスワード
   小僧さん、余計なお手間をとらせてしまって申し訳ありません。
先ほど昨日の投稿へのレスをさせて頂いた後で、この投稿に気が付きました。

>X 35.63 が固定で
>X1 が 36.33、36.23、…の様に変化するだけなので、
>距離テーブルに入る上位5位は、
>そのまま位置テーブルの上位5位になってしまうのかな、と。
>
>これは Satsuki さんの仕様によるものなのでしょうけど、
>もし X、Y にあたるものが緯度経度の様なものでしたら、
>2地点の緯度経度から計算される距離のTop5を求めなければいけないのかな
>と思った次第です。

そのとおりです。X、Yは緯度経度です。
そして、実際には
rs3![Kyori] = Sqr((Abs(rs1![X] - rs2![X1]) * 30.82) ^ 2 + (Abs(rs1![Y] - rs2![Y1]) * 25.15) ^ 2) / 1000
という計算式が入り、rs3の「Kyori」のTOP5をとりたいのです。
ところが、少数点以下13桁ぐらいの値で計算しても、計算結果は少数点以下がまったく計算されません。ここまで考える余裕がなかったので後ほど改めてお伺いするつもりでした。

【8157】Re:レコード削除
お礼  Satsuki  - 06/7/4(火) 11:27 -

引用なし
パスワード
   855さん、おはようございます。
早速のご教示ありがとうございました。

>こんにちは、まず小僧さんが言われたようにFor文の中のI = I + 1はいらないですね。
>あと↓これも修正必要ですね。
>>ご提示のコードですと rs1 が 2レコード目になった際、
>>rs3 が Close したままになっているためそこでエラーが返って来てしまいますね。

ご指摘ありがとうございます。この2点修正いたしました。
凡ミスでお恥ずかしいです。

>位置テーブルのrs2![X1]がrs2.MoveNextで値が変わるので、
>単純に「X1」フィールドの上位5位では無理そうですね。

こちらについては、小僧さんにも余計なお手間をとらせて恐縮しております。
実際には
rs3![Kyori] = Sqr((Abs(rs1![X] - rs2![X1]) * 30.82) ^ 2 + (Abs(rs1![Y] - rs2![Y1]) * 25.15) ^ 2) / 1000
という計算式なのです。この計算式が上手く作動しませんでしたので、とりあえず簡単な計算式で代用し、まずはコードを仕上げようと思っておりました。


>以下気になった点、、
>
>
>>rs3.Close
>>rs3.CursorLocation = adUseClient
>>rs3.Open "距離", cn, adOpenKeyset, adLockOptimistic
>わざわざrs3をClose・Openさせなくてもいい気がします。(何のエラーにもなりませんけど。)

私もおかしいなと思ったのですが、この3行をとると
「現在のプロバイダは並べ替え、またはフィルタリングに必要なインターフェイスをサポートしていません」と表示され、
rs3.Sort = "kyoriX DESC"のところが黄色くなります。


>>rs3.Sort = "kyoriX DESC"
>のあとに rs3.MoveFirst が必要かも。?

ありがとうございます。これは付け加えました。

>I = 0 はいらないですね。
>I = I + 1 も省いて。

はい、削除いたしました。

>このFor文にrs3のMoveNextがないので同じ値しか書き込みにいってないです。

Next i の前にrs3.MoveNextを入れました。


>>Do Until rs3.EOF
>>  rs3.Delete
>>  rs3.MoveNext
>>Loop
>
>この処理に入る前にrs3のMoveFirstが必要です。

rs3.MoveFirstを付け加えました。


>色々書きましたけど、Delete時のエラー解決にはなってないと思います。。
>実際に動かさずに書いた文章なので間違いがあったらすいません。

いろいろ教えていただきありがとうございます。
Delete時のエラーは現在もでます。
データ件数が多いので、毎回ワークテーブルのデータを消さないと時間がかかりすぎるため、この方法にしたのですが、他にいい方法があればと思います。

【8159】Re:レコード削除
回答  小僧  - 06/7/4(火) 11:47 -

引用なし
パスワード
   ▼Satsuki さん:
こんにちは。

Satsuki さんのコードを生かす形ですと
こんな感じになると思われます。

Public Sub keisan()
Dim cn As ADODB.Connection
Dim rs1 As ADODB.Recordset
Dim rs2 As ADODB.Recordset
Dim rs3 As ADODB.Recordset
Dim rs4 As ADODB.Recordset
Dim i As Long

Set cn = CurrentProject.Connection
Set rs1 = New ADODB.Recordset
Set rs2 = New ADODB.Recordset
Set rs3 = New ADODB.Recordset
Set rs4 = New ADODB.Recordset

rs1.Open "データ", cn, adOpenStatic, adLockReadOnly
rs2.Open "位置", cn, adOpenStatic, adLockReadOnly
rs3.Open "距離", cn, adOpenKeyset, adLockOptimistic
rs4.Open "TOP5", cn, adOpenKeyset, adLockOptimistic

'rs1.MoveFirst → 不要

Do Until rs1.EOF
  rs2.MoveFirst
  Do Until rs2.EOF
    rs3.AddNew
      rs3![kyotenmei] = rs2![拠点名]
      rs3![kyoriX] = rs2![X1] - rs1![X]
      rs3![kyoriY] = rs2![Y1] - rs1![y]
      rs3![kyori] = Sqr((Abs(rs1![X] - rs2![X1]) * 30.82) ^ 2 _
             + (Abs(rs1![y] - rs2![Y1]) * 25.15) ^ 2) / 1000
    rs3.Update
  rs2.MoveNext
  Loop

  rs3.Close
  'rs3.CursorLocation = adUseClient → adUseServerに変更
  rs3.CursorLocation = adUseServer
  
  'rs3.Open "距離", cn, adOpenKeyset, adLockOptimistic
  'rs3.Sort = "kyori DESC" → 下記行に集約
  rs3.Open "SELECT TOP 5 * FROM 距離 ORDER BY kyori DESC", _
               cn, adOpenKeyset, adLockOptimistic
  
  'i = 0        → 不要
  'For i = 1 To 5   → 不要
  Do Until rs3.EOF  '→追加
    rs4.AddNew
      rs4![kyotenmei] = rs3![kyotenmei]
      rs4![kyoriX] = rs3![kyoriX]
      rs4![kyoriY] = rs3![kyoriY]
      'i = i + 1  → 不要
    rs4.Update
  'Next i       → 不要
    rs3.MoveNext  '→ 追加
  Loop
  
  rs3.MoveFirst    '→ 追加
  
  Do Until rs3.EOF
    rs3.Delete
    rs3.MoveNext
  Loop

  'rs3.Close → 不要
rs1.MoveNext
Loop


rs1.Close
rs2.Close
rs3.Close
cn.Close

'以下追加
rs4.Close
Set rs4 = Nothing
Set rs3 = Nothing
Set rs2 = Nothing
Set rs1 = Nothing
Set cn = Nothing
  
End Sub

> 少数点以下13桁ぐらいの値で計算しても、
> 計算結果は少数点以下がまったく計算されません

数値データのフィールドサイズは
「単精度浮動小数点型」「倍精度浮動小数点型」
のどちらかになっていますでしょうか?
(怪しいのはワークテーブル:距離ですね…)

どこか一つでも長整数型のフィールドがあると
丸められて整数値で返ってきてしまいますよ^^


> Delete時のエラーは現在もでます。

位置テーブルの「拠点名」に重複はありませんか?
もし無いのであれば、距離テーブルの kyotenmei に主キー設定をすると
エラー回避になるかもしれません。


> kyoriX DESC

遠い拠点5箇所、で良いのでしょうか。
最寄5箇所を探すのであれば ASC のような気もしますが…。


以上まずはここまで…。

【8161】Re:レコード削除
発言  855  - 06/7/4(火) 16:07 -

引用なし
パスワード
   >rs3.MoveFirst
>Do Until rs3.EOF
>  rs3.Delete
>  rs3.MoveNext
>Loop
  
ちなみに、↑を cn.Execute "Delete From 距離" に変えてもだめですか?

【8162】Re:レコード削除
お礼  Satsuki  - 06/7/4(火) 17:06 -

引用なし
パスワード
   小僧さん、大変ていねいに教えて頂き、本当にありがとうございました。

>数値データのフィールドサイズは
>「単精度浮動小数点型」「倍精度浮動小数点型」
>のどちらかになっていますでしょうか?
>どこか一つでも長整数型のフィールドがあると
>丸められて整数値で返ってきてしまいますよ^^

そのとおりでした。「倍精度浮動小数点型」に変えたらちゃんと計算できました。

>遠い拠点5箇所、で良いのでしょうか。
>最寄5箇所を探すのであれば ASC のような気もしますが…。

ご指摘ありがとうございます。おっしゃるとおりです。
気がつかずにいるところでした^^ありがとうございます。

>位置テーブルの「拠点名」に重複はありませんか?
>もし無いのであれば、距離テーブルの kyotenmei に主キー設定をすると
>エラー回避になるかもしれません。

rs3.delete のところではエラーは出なくなりましたが、delete操作をしていないようで、rs3のテーブルにどんどんデータがたまって行きます。
ちなみに実験で下記の部分を消してみたらdelete操作をするようになりました。
不思議です。


>  rs3.Close
>  rs3.CursorLocation = adUseServer
>  rs3.Open "SELECT TOP 5 * FROM 距離 ORDER BY kyori DESC", _
>               cn, adOpenKeyset, adLockOptimistic
>  
>  Do Until rs3.EOF
>    rs4.AddNew
>      rs4![kyotenmei] = rs3![kyotenmei]
>      rs4![kyoriX] = rs3![kyoriX]
>      rs4![kyoriY] = rs3![kyoriY]
>    rs4.Update
>    rs3.MoveNext
>  Loop

【8163】Re:レコード削除
お礼  Satsuki  - 06/7/4(火) 17:10 -

引用なし
パスワード
   855さん、ありがとうございます。
教えていただいたとおりにしてみたら、できました。
下記のコードは一見問題ないと思うのですが、なぜかこの部分を通っていないようでした。


>>rs3.MoveFirst
>>Do Until rs3.EOF
>>  rs3.Delete
>>  rs3.MoveNext
>>Loop
>  
>ちなみに、↑を cn.Execute "Delete From 距離" に変えてもだめですか?

【8165】Re:レコード削除
回答  小僧  - 06/7/4(火) 17:24 -

引用なし
パスワード
   ▼Satsuki さん:
こんにちは。

うーん、Deleteの所がうまくいっていないのが残念ですが、
とりあえずは 855さんがご提示して下さった Execute で回避できそうですね。

以下、ご参考になれば幸いです。

Option Compare Database
Option Explicit

Dim cn As ADODB.Connection

Sub keisan2()
Dim rs As ADODB.Recordset
Dim strSQL As String

  
  Set cn = CurrentProject.Connection
  
  Call WorkDelete
  
  Set rs = CreateObject("ADODB.Recordset")
    
  strSQL = "SELECT * FROM データ"
  
  rs.Open strSQL, cn, adOpenForwardOnly, adLockReadOnly
  Do Until rs.EOF
    
    strSQL = "INSERT INTO TOP5 (kyotenmei, kyoriX, kyoriY)" _
        & "SELECT TOP 5 拠点名, [X1] - " & rs![x] & ", [Y1] - " & rs![y] & " " _
        & "FROM 位置 " _
        & "ORDER BY Sqr((Abs(" & rs![x] & "- [x1])*30.82)^2 " _
              & "+(Abs(" & rs![y] & "- [y1])*25.15)^2)/1000 ASC;"

    cn.Execute strSQL
    rs.MoveNext
  Loop
  
  rs.Close: Set rs = Nothing
  cn.Close: Set cn = Nothing

End Sub

Function WorkDelete()
Dim strSQL As String
  strSQL = "DELETE FROM TOP5"
  cn.Execute strSQL
  
  strSQL = "DELETE FROM 距離"
  cn.Execute strSQL

End Function

【8167】Re:レコード削除
お礼  Satsuki  - 06/7/4(火) 17:54 -

引用なし
パスワード
   小僧さん、ありがとうございます。

こんなにすっきりしたコードでできるのですね。
とても参考になります。
といってもかなり難しく、解読できるかどうかわかりませんが、勉強してみます。
とても助かりました、本当にありがとうございました。

1226 / 2272 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
1078220
(SS)C-BOARD v3.8 is Free