愚者の経験

「また今度」はほとんどこない

カテゴリーアーカイブ: Access

[Access][SQL Server]パススルークエリで「レコードが大きすぎます」のエラー

ODBCでパススルークエリ書いていると突然発生…。
どうやら文字列型のフィールドでの合計文字列数に上限があるみたいです。レコード長2000バイトみたいですね。
メモ型にするとこの制約から外れる(合計文字列数に含まれなくなる)んですが、パススルークエリって適当に型変換してますよね?

でもとりあえずnvarchar(max)にcastすればメモ型として見てくれる模様。
ODBCは意外な場所に落とし穴があって大変です。

[SQL Server][Access]日時のフィールドで苦労した話

Accessで時刻を入力するのは若干面倒くさい。最終的に使いたい項目が日時だとしても
「日付」と「時刻」の別にフィールドを設けることが多いです。以下長文ごめんなさい。

テキストを1つにすると日付だけ既定値で入れられることが出来たとしても
時刻を続けて入力するにはキャレットを移動させるしかなく、F2キーやマウスをクリックしたり矢印キーを
使用するのを避けられないのが主な理由です。(テキスト毎にEnterイベントでSelStart入れればそんなもんですがそれもちょっと…)
他の理由としては自前のカレンダーや時刻の入力フォームが別にある場合該当のテキストへの入力が複雑になるということもあります。

さらに大きな問題としてOSの時刻の表示が「H:mm」になっているせいで定型入力が「00:00」系で例えば「09:00」
と入力しても再表示時に「9:00」となって、フォーカスすると「9_:00」となって出るときにエラーになって安定しなかったり、
時刻に24時以上を打ち込みたい場合はどうしようもないという理由で最近は時刻は文字列型にしています。
(エラーの方に関しては私が体験したもので必ずでるというわけではないです。今やってみても再現出来ない…。)

そんなこんなでフィールドを2つに割ったとして今度は利用する際に毎回「[日付]+cdate(nz([時刻],”00:00″))=……」とか
しなければいけなくなるのですが、SQLServerを利用している場合は「計算列」という機能があるので
これを使うんですがちょっと問題があります。

24時以上を入力しない場合は計算列の数式に「[日付]+cast(isnull([時刻],’00:00′) as datetime)」とやればいいんですが
「列’xxxx’の数式を検証中にエラーが発生しました。変更を取り消しますか?」と言われてしまいます。
うーんあってるはずなのに…多少書き方を変えても同じです。
どうすればいいかというと上記警告を無視して(上記ダイアログを[いいえ]で突破する)、テーブルの保存時にも似たようなことを
警告されますが再度無視し、テーブルを見ると…ちゃんと出来てますorz
この時castで書いたはずの型変換はconvert(datetime,isnull([時刻],’00:00′))に書き換わっていました。
これで書けばいいのか~とconvertで書いてもやっぱりエラー笑

「悩みまくったのは一体何だったんだ」と思いました。インデックス貼るまでは。
続いてアプリがこなれて仕様も固まってきた頃、速度改善のためにインデックスを作成しようと思って
上記の計算列を選ぶと「インデックスの作成に失敗しました」という趣旨のエラー発生。
「あ~計算列はインデックスキー列に含めないのね」と勝手に思って仕方なく付加列に追加…
出来ません!再度エラーが出ます。
なんで?と思って調べたら、以下の情報がヒット
https://msdn.microsoft.com/ja-jp/library/ms189292.aspx
「決定的」であるかどうかが重要で文字列型を日付にconvertする時は値が決定的になる第三引数が必要だそうです。
なので「convert(datetime,isnull([時刻],’00:00′),108)」とすると保存時にエラーは出ますが、インデックスは使えるようになりました。

うーん。言いたいことは分かるんですがエラー出るのは気持ち悪い。とりあえず24時対応しましたところ
(([日付]+CONVERT([int],left(isnull([時刻],’00:00′),(2)))/(24))+CONVERT([datetime],(CONVERT([varchar](2),CONVERT([int],left(isnull([時刻],’00:00′),(2)))%(24))+’:’)+right(isnull([時刻],’00:00′),(2)),(108)))
これだとエラー出ないんですよね…不思議。

[Office 2013][Access]Access2013の計算値が表示されなくなる現象

Access2013なんですが、たまにおかしい現象が出ます。
・コントロールソースに計算を入れているテキストボックスの表示が表示されなくなる
・サブフォームコントロールの親リンクフィールド、子リンクフィールドが機能せず何も表示されなくなる
主にこの2つです。
またたまに「コントロールをクリックすると表示される」という状態になることもあります。
私が知るかぎりこれはかなり厳しい状況で、すぐ思いつくことをしても大体直りません…
・最適化/修復
・デコンパイル
・PC再起動

現状戻せている方法は「システムの復元」とAccessのバージョン切り替え(Accessを複数バージョンインストールしている場合のみ)です。
おそらくAccessを再インストールしても直るでしょう…また修復で直るかは未確認ですが
クライアントのPCでしていただくにはあまりにも重すぎます…orz

試しに同じプログラムをAccess2010で動かすとちゃんと表示されるので
ファイルが壊れているとかプログラムが間違っているということではありません。
WindowsUpdateも自動で当てているPCだったのでおそらくAccess自体も最新だと思います。

当初WindowsUpdateでなにか変わったのかと思ったのですが復元先のチェックポイントまでに
「自動復元ポイント」しかなかったとしても、それで直るパターンがありました。
なのでシステムに影響があって変わったというわけでもなく、突然上記の症状になるということになります。

OSはWindows7とWindows8.1の両方で発生したことを確認しています。

この方も多分同じ症状だと思います…よく見たらこの方はAccessの修復をされたみたいですね。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11125283376

あんまりこんなこと言いたくないんですが、Micr○softさんなんとかしてください、お願いします。…m(__)m

2015-1-23 追記
「[ハードウェアのグラフィック アクセラレータを無効にする] のチェックを外す」が効くかもしれません(未確認)
アンインストールする前に確認出来た方いらっしゃれば教えていただければ。
ただ、これVBAで設定する方法がわからない…VBAでレジストリいじるの入れようかな。

さらに追記
Access2010sp2でも発生…サブフォーム内のテキストボックスのコントロールソースに「=[コンボボックス名].column(1)」とか
書いてあるのも空白になっていました。もちろん合計欄見えず、親子リンク動かず。
動くPCと動かないPCが出るのでファイルサーバーのせいではなさそう。クライアントOSは全てWindows8.1 pro 64bitで
PCを再起動しても直らず、Accessを修復すると直りました。しかしサーバは開発用にAccess2013がインストールされているのですが
Access2013を修復しても現象は直りませんでした。クイック、オンライン両方でダメです。

原因が不明で再現性もなく、まったくわかりません…異常が発生したPCのプログラムとサーバのデータを持って帰り
Windows 7のAccess2013で動かしてみましたが再現せず、Windows 8.1のAccess2010で動かして見ても再現せず。
一体どうすればいいのやら。

[Access][ODBC][VBA]RefreshLinkとリンクテーブルマネージャでの再リンク

同じことやっているんだろう…そう思っていた時期が私にもありました。
Viewに適用するとRefreshLinkは主キーの擬似インデックスが外れますが、リンクテーブルマネージャは
外れません。なぜでしょう…これのせいでRefreshLinkがかなり使いづらいです。

[Access][VBA]Accessの開発方法考察(模索中)

・単純かつ頻繁に出るコードは標準モジュールのPublic Functionに集める
フォームのオープン、クローズ
コンボボックスのカラム値を代入
リストボックスを複数選択した場合の値を連結
Tempvarsに値を代入
リボンの表示非表示切り替え
RGBを6桁で入力する
・ODBCでパススルークエリを使う場合はなるべくパススルークエリを直接
 フォームのレコードソースにせずにワークテーブルを利用する
(私が知らないだけかもしれないが)パススルークエリで行を最新に更新する場合
Requeryでパススルークエリの対象行全てを問い合わせるしかないため。
面倒だがトラフィックを考慮し、ワークテーブルに対して別のパススルークエリで
更新対象行のUpdate(またはDeleteとInsert)を行ってフォームのレコードを更新する。
パススルークエリが1行しか表示しない場合などはそのままでいいと思います。

[Access][ODBC]新規レコード確定時に入力データが別レコードに化ける

これを最初に見た時「ん?」となりました。以下の状況で発生します。
0.環境はSQL SERVER 2012または2008 R2とAccess2010のODBC接続(他でも起きるかはわかりません。確認出来たのはこの組み合わせ)
1.入力するテーブル[テーブルA]の主キーがidentityである
2.入力するテーブルのafter insertトリガーが設定してありその中でidentity列があるテーブル[テーブルB]にinsertを行う。
3.テーブルBの新規identityがテーブルAの主キーデータとして存在している
この状況で発生します。なんとなくこう書いただけでどうなるか検討がつく方は素晴らしいです。

テーブルAに新規にレコードを入力すると
1.テーブルA入力中は(新規)になっている(Bの次のidentityは1)
odbc1
odbc2
2.入力確定時にidentityを取得しに行く
3.入力確定時にテーブルBにinsertしているので取得するidentityはテーブルBのもの
4.テーブルAの(新規)の部分がテーブルBのidentityになりその値がテーブルAの主キーとしてデータが取得される
確定前
odbc3
確定後、レコードがidentity1が1のレコードに化ける(identity1に1が2行ある…)
odbc4
テーブルBは1が挿入されています。
odbc5
テーブルAはリクエリすると元に(?)戻る
odbc6

・回避方法
入力テーブルかトリガーのidentityを使わない…しかないのか?

テストテーブル

CREATE TABLE [dbo].[テーブルA](
	[identity1] [int] IDENTITY(1,1) NOT NULL,
	[value1] [int] NULL,
	[value2] [nvarchar](50) NULL,
 CONSTRAINT [PK_テーブルA] PRIMARY KEY CLUSTERED 
(
	[identity1] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
go
CREATE TABLE [dbo].[テーブルB](
	[identity2] [int] IDENTITY(1,1) NOT NULL,
	[value] [int] NULL,
 CONSTRAINT [PK_テーブルB] PRIMARY KEY CLUSTERED 
(
	[identity2] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

テストトリガー

CREATE TRIGGER [dbo].[utr_afiテーブルA]
   ON [dbo].[テーブルA]
   AFTER INSERT
AS 
BEGIN
	SET NOCOUNT ON;

	insert dbo.テーブルB(value)
	select 1

元に戻したいときはこれで
DBCC CHECKIDENT (テーブルB,RESEED ,0)

[Access]データシートの幅が保存されない!!

今更感がある話題ですが…
Access2010以降(といっても2013は知りませんが)データシートの幅が保存されにくくなっています。
以前は列幅を変更しただけで変更フラグが立って閉じようとすると「変更を保存しますか?」的な
ダイアログが出ていましたが、Access2010は出ません。
「列の非表示」や「列の再表示」をすることでようやく変更フラグが立つようで、
列幅を変更しただけでは変更していない→保存する必要なし→保存しない
と(おそらく)なってなにも変わりません。

[Access][VBA]今更…フォーム側のPrivate Functionはコントロールから直接Call可能だった…

これホントですか…
今まで標準モジュールに書いたPublic Functionしか呼べないと思ってました。
「RelayCommand」とか考えた意味なし…
まあ「見えないから使えない」と思い込んでいた私も悪いのですが…。

1.フォームデザインでコマンドボタン配置
call1

2.フォームのモジュールにPrivate Function記述
call2

3.フォームデザインでコマンドボタンのイベント→クリック時に記述
もちろん候補には出ない(出してほしい笑)
call3
call4

4.クリックすると実行される
call5

これみなさん知ってます?Access5年近く触っているけど気づきませんでした…。
ちなみにPublicにしたところで他のフォームのコントロールから呼べるかというとできないと思います。
イベントプロパティに「=[Forms]![フォーム1].TestCall()」等しても「指定した式の構文が正しくありません。」と怒られてしまいます…

またがる場合は標準モジュールにということだと思うことにします。

[Access]サブフォームの再読み込み時のレコード移動をなんとかする

自分もどこかに書いてるかもしれませんね…手っ取り早く防ぐには
「サブフォームコントロールをRequeryする」です。

ただこの方法でカレントレコードを移動しない条件として
・フォームの「フィルタ」を使用しない
・フォームの「並び替え」を使用しない
があります。上記のいずれかが適用されている場合は
カレントレコードは最上のレコードへ移動してしまいます。

しかし幸いなことに「リンクフィールド」はOKのようです。

上記の方法が使えない場合は
・カレントレコードを変数に格納
・Requery
・カレントレコード戻す
・スクロールバーを戻す
をしないと完璧には戻らないので結構厳しいです…

追記:なんと親フォームの「フィルタ」「並び替え」をしていてもダメなようです…

[Access 2013]リボンの最小化のレジストリ値が変わった

かなりどーでもいいですが、最近記事を書く暇がないので…

リボンを最小化するにはレジストリを変更して実現できました。

Access2007の場合→HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Common\Toolbars\Access
Access2010の場合→HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Toolbars\Access

の値「QuickAccessToolbarStyle」をデータ[4]で最小化、[0]で非最小化していたのですがAccess2013の場合キーは

HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\Toolbars\Access

で値「QuickAccessToolbarStyle」もそのままですがデータがなぜか変更になり[20]で最小化、[16]で非最小化となっています。

VBAで制御している方は気を付けましょう。