SSブログ
テーブル設計 ブログトップ

コード項目の「前ゼロ」文化 [テーブル設計]

 学校などでプログラムを勉強している場合には、まず遭遇しない事柄だと思います。
 実際の開発現場では、時としてこういった設計のシステムに出会します。

 「前ゼロ」または、「前ゼロ埋め」とは。(私の周りでは、こういう表現でした)
 「5桁の数値で、123」を表現する場合、「00123」となることを、こう言います。

 前にゼロを付けて数値を表現する事は、いろいろな場面であるのですが、ここではシステムでのコード項目(商品コードとか顧客コードとか)について書きます。

 数値の前にゼロが付くというのは、BASICやC言語あたりから(ちょっと古いか、今時は何から始めるんだろう?)プログラムを始めた人には、あまりピンとこない事だと思います。
 COBOLでの数値の表現が、こうなっていることに由来していると思われます。

 COBOLでは、数値項目を桁数指定で定義します。5桁で定義した場合、その領域には、「00123」のような表現で、必ず5桁が記録されます。記録する桁数が、定義された桁数以下だった場合、上位の桁には、「0」が入ります。

 現在のデータベースを用いたシステムでも、同じようなデータの持ち方になるように、設計されることがあるようです。
 データベースの数値項目は、「数値」としての情報しかもてませんので、前にゼロを付けた状態は記録できません。記録できる数値の範囲がどうであれ、数値の「123」は「123」です。
 では、どうするかというと、テキスト項目にします。文字なので「00123」そのままを記録することができます。
 しかし、テキスト項目は、数値項目と比べて、必要な記憶容量や処理の負荷で不利になります。
 古い資産の焼き直しとかでない限り、この設計は有用ではないと思います。

 内部がどうなっているかは、利用者からするとどうでも良いことなのですが、時々利用者への配慮が足りないシステムに出会します。
 例えば、数値5桁の「商品コード」項目があったとします。
 そこで、「00123」というコードの商品を呼び出すとします。
 私的には、「123」とだけ入力したいのですが、システムは「00123」と入力しなければ受け付けられないようになっています。
 そこの所は、プログラムで良きに計らって頂きたい所なんですが、そうなってない物もあるわけです。5桁なら、まあ許せるかも知れませんが、これが7桁とか9桁になったら、キーボードの「0」がすぐ壊れます。

 若い開発者が、古いシステムをお手本にして、何の疑問も持たずに、コード項目を文字項目で作るようになって欲しくないと、私的には思ってます。

 蛇足ですが、下記のような用語があるようです。

・ゼロパディング・・・数値が規定の桁数に満たないとき、桁を0で埋めること。
・ゼロサプレス・・・前(左側)から連続する0を取り除くこと。

 さらに蛇足です。
 文字項目のコード項目で、後ろスペースを持つような作りにはしない方が良いと思います。
 どーもSQLの条件とかでは、後ろスペースは無視されて、スペース数やありなしを判定できないような感じだったので。


テーブル設計 数量と単価と金額 [テーブル設計]

 例えば売上データを格納するテーブルを作成するとして、以下のような項目を定義します。

○売上データテーブル
・売上日
・商品コード
・数量
・単価
・金額

 特に何のひねりもない、単純な構成です。

 ここで、ある程度プログラムをやったことがある人なら、一つ気になる部分があると思います。

 「金額」の項目は、「数量×単価」で計算できるから、テーブルの項目として持つ必要があるのか?

 「金額」の項目をテーブルに持たなければ、その分データを記録する容量が少なくて済むので、効率的と言えます。無駄を省くのは良いことです。

続きを読む


テーブル データ型について [テーブル設計]

 テーブル項目のデータ型の決め方は、それぞれの場所の文化とか、過去の資産のしがらみとか、個人の好みとかが出る部分なので、一概になにが正しいとは言えないところがあります。
 ここに書くことは私がそう思うだけのことなので、自分の意志をお持ちの方はその道を貫いて頂いて、まだ無垢の人はあまり鵜呑みにしないでください。 

 あ、一応ここはACCESSのテーブルでの話をします。
OracleとかSQLServerはまた違う世界ですので。

 とりあえず、データ型についていろいろです。

・テキスト型
 正しい使い方は、文字を入れる用途に使うこと。例えば、名称、単位名、名前、郵便番号、住所、電話番号・・・おや、意外と出てこない。
 間違った使い方は、数字しか使わないコード項目、日付、時刻に用いること。JANコードとかは13桁あることと、前ゼロやいろんな特殊事情が絡むことがあるので、テキスト型にしておくのが無難。
 数字しか使わないコード項目をテキスト型すると、数値と数字の違いで面倒なことになる可能性があるので止めましょう。日付、時刻もテキスト型にしているのをよく見ますが、これも日付型があるので。
 テキスト型はいろんな処理で不利になる(処理時間がかかる)ことが多いので、間違った使い方をすると、パフォーマンス悪化の原因になります。
 フィールドサイズに文字数を指定します。バイト数ではありません。半角英数も全角漢字もすべて1文字でカウントします。余談ですが、ACCESSはUnicodeだから、全部2バイト扱いです。
 ・・・では、例のVistaの4バイト文字は?
フィールドサイズを「6」にして、4バイト文字を入れてみたところ、3文字しか格納できませんでした。6文字→12バイト、4バイト文字が3文字で12バイト。とりあえず格納できただけすごいかも。が、画面上では、漢字の真ん中にカーソルが来たりして、怪しさ満点でした。(ACCESS2000で実験)

・メモ型
 255文字を超えるテキストを扱いたいときに使います。私は使ったことないです。
ちなみにOracleはvarchar2で4000バイト、SQLServerだとcharまたはvarcharで8000文字まで指定できます。

・数値型
 もちろん数値に使います。例えば、金額、原価単価、売価単価、数量、重量・・・うーん、またまたあんまり出てこない。
 続いて数値型のフィールドサイズについて。

・バイト型
・整数型
・長整数型

 それぞれに値の範囲があって、その範囲内ならそれを指定するのが良いと思われがちですが、この指定は使わない事をおすすめします。値の範囲からして内部処理を察するに、値を扱う上ではもっとも効率の良いデータの持ち方なのですが、一般的な業務システムには適合しません。業務システムを構築する場合、項目の値の範囲は桁数でお客様と話をして決めるので、十進型の桁数指定が都合が良いんです。説明するのに、「ここは2,147,483,647以内で入力して下さい。」なんてかまずに説明できないし。
 もっとも、金額の項目あたりになると、長整数型でも足りません。オーバーフローの原因で一番多いのが、「項目が長整数型だった」なんです。テーブルに限らず、VBの処理でもね。

・単精度浮動小数点型
・倍精度浮動小数点型

 一般的なシステムでは使いません。私も使ったことがありません。よく言われることですが、これらの型は、科学技術計算や確率統計の値を扱う時に使用します。
 まちがっても、小数点ありの項目だからと言って、浮動小数点型にしないで下さい。これらの項目は、ある値そのものを指し示す表現ではなく、指したい値に限りなく近い値を持つように作られているからです。浮動小数点というデータ表現の仕組み自体が難しいので、それを理解してから使いましょう。(誤差とか桁落ちとかイコール演算とかその辺の知識なしで扱うのは危険です)
 通常、小数点の値は、固定小数点で扱うのが一般的です。
 そーいえば昔、浮動小数点の項目を集計したら、1の桁が合わないんだけどって質問を受けたことが・・・。

・レプリケーションID型
 ・・・こんなのあったんだ。すいません、なんなのかわかりません。
使ったことないです。

・十進型
 私は数値はすべてこれを使います。例えば金額や数量、マスタのコード項目等ですね。業務系システムは何も考えずに十進型で良いと思います。過去の仕様を踏襲することも多いし。
 整数部と小数部をそれぞれ桁数で指定します。値の範囲が一般人にも直感的で分かり易いし、システムの仕様としても一目瞭然です。数値は基本的に十進型を使って良いと思います。
(ええ、処理効率は、整数型とか長整数型より劣ります。)
 だいたい金額なら9桁、数量なら7桁、金額集計項目は12桁で指定することが多いです。
 ACCESSの十進型は、他DBとの互換性を確保するために設けられたせいなのか(どうかはわかりませんが)、初期は結構不具合があった様です。今はACCESS2000でも、最新パッチの状態なら安定して使えると思います。

・日付/時刻型
 日付を扱うときは、日付/時刻型を使いましょう。1つの項目に時刻まで記録できるので便利です。が、日付/時刻型の仕組みについて、ちょっと知識があった方が良いかもしれません。
 COBOL好きの人は、日付を文字8桁で作りがちですが、もうそれは止めた方がいいと思います。どーせプログラム上では日付型変数に入れて扱うわけだし、日付用に準備された便利な関数を使うためには、日付型に変換してやらないといけないので。
 余談ですが、日付型のデータを日付型以外の物に取り出す場合(たとえばテキストボックスに表示とか)、かならずFORMATで書式を指定しましょう。たまーに、「地域のオプション」の日付形式をいじる人がいて、こちらが意図した内容にならないことがあるので。Where句の組み立てとかでこれを忘れると、大変なことになります。

・通貨型
 十進型以外で数値項目を定義するなら、二番手はこれかなと思います。通貨型にしておけば、大抵の用途では桁が足りなくなるような事が無いし、小数も4桁まで扱えます。
 MDBオンリーならお薦めしておきます。

・オートナンバー型
 テーブルにデータを追加していくと、自動で連番を振ってくれる便利な機能です。
が、自動であるが故に、番号を初期化したいとか、とんだ番号をなんとかしたいとか、そういうときに融通が利きません。後で困ります。なので使わないほうがいいです。はい。
 一応、最適化で初期化されるらしい。

・Yes/No型
 TrueまたはFalseまたはNullの状態を記録するのに使います。このデータ型もACCESS固有かな。Oracleにはありません。
 いわゆるフラグ的なデータを扱います。私はこっちより、十進型1桁を使います。(普段Oracleを使ってることが多いので、一緒の方がいい・・・)

・OLEオブジェクト型
 何でも放り込めるデータ型です。難しいのと、使う機会が無かったので、詳しくは知りません。

・ハイパーリンク型
 これも使った事無いです。

 かなり偏った主観だと思いますが、ここ数年はこの考え方で落ち着いてます。

 あと、項目名に日本語(かな漢字)を使うのはやめた方がいいと思います。まず、入力し辛い。そして、不具合・・・は、だいぶ無くなりましたが、それでもいろんな問題を引き起こす一要因になりやすいので、避けておいた方がいいです。ってね、ACCESSのサンプルや、ウィザードの例が日本語なんだな・・・。


雑記 日付型について [テーブル設計]

 ある年代を境に、周知されていない日付型についてちょっと。

 VBA(およびVB)やテーブルのデータ型には日付型というのがあって、日付と時刻の扱いに特化した作りになっています。そもそも数値型は数値演算用、文字型はただ文字列を記録するためだけに作られているので、日付・時刻という特殊なルールをもっている値は、数値型やテキスト型では不都合が多いのです。
 どういう事かというと、数値型で1を加算する場合は、単純に1を加えてやれば済むのですが、日付だとそうはいきません。1日後の日付を求めようと思ったら、今日の日付の「日」の部分を取り出して、1を足して、さらに「月」を取り出して、月末日付を超えていないか確認する必要があります。月末日は月によって31、30、28と変わります。さらに閏年があるので、気が遠くなります。日の繰り上がりを考慮し、さらに月の繰り上がりも考慮しないといけません。日付型を使わない日付処理は、めんどくさいのです。昔COBOLが主流だった頃はあたりまえにルーチン書いてましたけどね。月末日とかはめんどくさいから50年分くらいテーブルに持っちゃったり。

 日付型で「日」を加減算していく場合、単純に日数を加減算してやればOKです。

例) datA = datA + 5

 日付以外の単位、「年」「月」および「時」「分」「秒」の加減算は、DateAdd関数を使います。

五ヶ月後を求める
例) datA = DateAdd("m", 5, datA)

第一パラメタに、加減算する単位を指定します。
年・・・YYYY
月・・・M
日・・・D
週・・・WW
時・・・H
分・・・N
秒・・・S

これだけ覚えていれば不便は無いはず。

 日付型から、「年」や「分」といった、特定の単位の値のみを取り出したいときは、以下の関数を用います。

Year(datA)  '年
Month(datA)  '月
Day(datA)  '日
Hour(datA)  '時
Minute(datA)  '分
Second(datA)  '秒

 で、これの逆をする関数が、DateSerialとTimeSerialです。
年・月・日、時・分・秒それぞれの値から、日付型に変換します。

例)
datA = DateSerial(2006, 1, 2)
datA = TimeSerial(12, 15, 30)

 このDateSerial関数は、ちょっとおもしろい使い方ができて、月末日を求める時に便利です。

例)システム日付の月末日付を求める
datA = DateSerial(Year(Date), Month(Date) + 1, 0)

0とか、マイナスを指定してもOKなんです。
1日は1なので、0を指定すると、その1日前を返してくれます。

 月初(1日)なら、こんなのもありでしょうか。
例) Debug.Print Format(datA, "YYYY/MM/\0\1")

 最後に、日付型の内容を、文字列として取り出すときは、必ずFormat関数を使いましょう。なにも指定しないと、そのパソコンの設定の影響を受けて、こちらの意図した動作をしてくれない原因になります。

例) Debug.Print Format(datA, "YYYY/MM/DD HH:NN:SS")

 「分」は「NN」です。お間違えなく。

 日付型は内部的には小数点ありの数値になっています。整数部分が日付を表すシリアル値で、小数部分が時刻を表しています。
 ちなみに、シリアル値が0の場合、
? FORMAT(0,"YYYY/MM/DD HH:NN:SS")
1899/12/30 00:00:00
を指します。
 最小の日付は、100年1月1日です。
 最大値は9999年12月31日 23時59分59秒まで。
 VBAの変数はNull値を持てないので、「値なし(またはローバリューとか)」の状態を表現する場合は、代わりに最小の日付を使うなどの工夫が必要になります。

 「20070515」のような、スラッシュなし数字8桁を日付型変数へ代入する場合は、以下のような変換処理をします。

例)datA = CDate(Format("20070515", "@@@@\/@@\/@@"))

 COBOLのシステムとかでは、日付を8桁の数値で持って、特殊な状態を表すのに「00000000」や「99999999」を使用していることがあります。当然日付型でこれらの値を扱うことはできないので、注意が必要です。
 日付として正しいかどうかを調べる関数として、IsDate関数があります。が、こちらの思惑と違う判断をすることが多々あるので、ある程度の工夫が必要になります。

※ 「\」(バックスラッシュ)は「¥」半角の円記号です。


リレーションシップの設定は必要か? [テーブル設計]

 ACCESSにはリレーションシップというテーブル間の結合を定義する画面があります。         

 この機能自体は、リレーショナルデータベースの定義をよく表しているというか、テーブル間の関係性、どれがマスタで、どれがデータで、どの項目がキーになっていて関連づけられているかを明確にできるので、とても大事そうに思えます。

 が、私は設定してません。

 使ってる人に遭遇したこともありません。(私の狭い世間で)

続きを読む


テーブル設計 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。