変奏現実

パソコンやMMORPGのことなどを思いつくまま・・・記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

この画面は、簡易表示です

MySQL

[MS-ACCESS]エクスポートとbit型

MDBファイルのテーブルをMySQLにエクスポートしてみると、テーブルの構成に色々と問題が出てくる。

特にNULLを許可するかどうかが一番の問題。

作ったプログラムが許容できなかった場合を考慮して、フィールドが Not NULLだったり、初期値を設定してあれば、それと取り込んでALTER TABLEすれば大体問題は解消。

AutoNumberもNIQUE KEY扱いしてAUTO_INCRIMENT属性を付ければ何とかなる。

[MySQL]ODBC接続でフィールドの番号を振り直してみる

しかし、それでは気が付かないモノもあった。

Bit型のフィールドだ。

MS-ACCESSではYes/NoのフィールドがBit型(長さ1)のフィールドに変換されるがNULLはOKとなっている。でも大丈夫かと思ったら、そうでは無かった。

MS-ACCESSの連携フィールドではチェックマークになる。

このフィールドがある場合に「*」でレコードを追加する際に先のチェックを入れないと、何故かBit型のフィールドに NULL が入ってしまう。

それでも、MS-ACCESS上で支障がなければいいが、そうなっていない。

ビューの上では追加した行にDELETEマークが並ぶ。ビューを最新表示すれば消えるが、その行を編集や削除をすると、

データの強豪

と、いつもの頓珍漢なメッセージが出てしまい、何が原因か全く判らない状況に陥ってしまう。しかし、サーバやPCを再起動しても、リンクテーブルのビューでも編集や削除をすると、同じメッセージが出るので、

MSーACCESSが何かトチったことが判る。

PHPMySQLでBit型がNULLになっているとこを0に変えると問題は解消される。

つまり、INSERTで設定した(つもりの)値と違う内容がレコードに入っていたので、誰かが書き換えたに決まっている!とMS-ACCESSは判断をしたらしい。

実際にはINSERT時はBitフィールド型が未設定の様だ。それをやっちまっているのはMS-ACCESSなのかMySQLのODBCドライバなのかは判らないケドね。

SELECT * FROM テーブル名 WHERE Bitフィールド名 IS NULL;

なレコードをポチポチ直すものいいけど、

UPDATE テーブル名 SET Bitフィールド名 = 0 WHERE Bitフィールド名 IS NULL;

で焼き尽くしても、どうせ、すぐに増えるから・・・直ぐに!

ALTER TABLE テーブル名 CHANGE Bitフィールド名 Bitフィールド名 BIT( 1 ) NOT NULL DEFAULT b'0';

と、BitフィールドでNULLを禁止し、初期値も0にした方がいいだろう。

※bit(2)とかbit(3)に変換されるフィールドもあるのかもしれない。(ケド

一応、

SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE data_type = 'bit';

で見ると、bitフィールドが意外にいっぱいあったりする。

エクスポートする際は、bitフィールド型も要注意。(ダナ

SET sql_mode='PIPES_AS_CONCAT'; select 'UPDATE `' || table_schema || '`.`' || table_name || '` SET `' || column_name || '` = 0 WHERE `' || column_name || '` IS NULL;',
 'ALTER TABLE `' || table_schema || '`.`' || table_name || '` CHANGE `' || column_name || '` `' || column_name || '`  BIT(' || NUMERIC_PRECISION || ') NOT NULL DEFAULT b''0'';'
 FROM information_schema.columns WHERE data_type = 'bit';

これを実行すると全データベースのBitフィールドをサッパリにするSQLを吐き出す。ALTER TABLEは1行づつ整合性チェックが入るみたいなのでレコード数が多いと結構時間がかかる。(ッヨ!

※SETはconcatを使うとミスが見つけにくいので、 || を使ったから。

※UPDATEしてるのは、NULLデータがあるとALTER TABLEでNOT NULLが整合性エラーで弾かれるから。

さて、絶対安全?MS-ACCESSからMySQLへのエクスポートのVBAに手を入れなければ・・・



[MySQL]ODBC接続でフィールドの番号を振り直してみる

MySQLのAutoInc属性は0かNULLを設定した時に自動的に番号を振る機能なので、バックアップ・リストアを繰り返していると、気が付けば、数値が重複していたりする。
※UNIQUE KEYにしておけばそんなことは起きない(ハズ

そんな困った時は

SET @i := 0 ;
UPDATE テーブル名 SET フィールド名 = (@i := @i + 1) ;

なSQLをphpMyAdminから叩けば良いらしいんだけど、MS-ACCESSとかEXCELの【ボタン】から、ODBCでExecuteしてみると・・・・

エラる。

;の後に文字があるせいらしい。

試しにストアードプロシージャっぽく、

“BEGIN
SET @i := 0 ;
UPDATE テーブル名 SET フィールド名 = (@i := @i + 1) ;
END”

をExecuteすると、BEGIN…. 何ソレ美味しいの?状態。

仮にストアードプロシージャを作ったとしても

CALL 採番(’テーブル名’, ‘フィールド名’);

の様に直接パラメータは書けないので、@引数を使って

SET @p1=’テーブル名’;
SET @p2=’フィールド名’;
CALL 採番(@p1, @p2);

と呼ばないといけないらしい。てか、行数増えてるし・・・(汗

@変数を使うSQLをODBCで扱うのは、土台無理なんだろうか?

正解は、

1行づつやらせれば良い。

Dim sql(1) As String
sql(0) = “SET @i := 0 ;”
sql(1) = “UPDATE テーブル名 SET フィールド名 = (@i := @i + 1) ;”);

あるいは
Dim sql() as String
sql = split(“…….”, vbCrLf)

for idx =lbound(sql) to ubound(sql)
ds.Execute(sql(idx),dbSQLPassThrough)
next

2行目の処理時間は結構長い。

安易に・・・

Dim cnt As Integer
set rst = odbcConn.OpenRecordset(テーブル名)
Do While rst.EOF = false
rst.edit()
cnt = cnt+1
rst(フィールド名) = cnt
rst.update()
rst.MoveNext
Loop

な事をしてしまうと、レコードが少なければ数秒で終わるけど、全レコードの全フィールドを読み取る事になるので、何万レコードもあったら、何時間かかるか判らない。




top