また勉強し直したい。
RDBMS
とうか、KVSだのNoSQLだのDBのシステムによって大きく違うと思うけれど、
私は
MySQL
とちょっと
PostgreSQL
とか
SQLite
とか触ったくらいなしょっぱい男です(先の言い訳)。
主に扱うのは
MySQL
で、そのくらいしかついていけません(わかるとは言いません)。
「
MySQL
ってそうなんだ〜。
Oracle
だとこうなんだよー、きゃははー」とか言われても、しょんぼりとしかしません。
Rails
使ってると、
マイグレーション
ファイルでDBのテーブル定義して、
rake db:migrateで
マイグレーション
ファイルを元にテーブルが作成されちゃう。
ここで使うDBによって、うまいこと作られる型に差異がある。
参考は
[
Ruby on Rails
: データ型一覧&DB対応表 - kosuke-komiya.info/
wiki
]
http://kosuke-komiya.info/wiki/index.php?RubyOnRails_Types
[
ActiveRecord
と実際のDBの型の対応を確認する - @sugamasao.blog.title # => ”コードで世界を変えたい”]
http://d.hatena.ne.jp/seiunsky/20101220/1292813809
この辺とか。
しかし思う。
tinyint(1)って、
MySQL
のDriverとか
ActiveRecord
がtrue/falseに変換してるだけで、
実際±127(符号無しなら0〜255)まで入れられるよなーと。
8ビット(1バイト)ですね。
確か記憶だと、
bool, booleanは、内部的にtinyint(1)になる
エイリアス
みたいなもんだった気がする。
[
MySQL
::
MySQL
4.1 リファレンスマニュアル :: 6.2 カラム型]
http://dev.mysql.com/doc/refman/4.1/ja/column-types.html
TINYINT[(M)] [UNSIGNED] [ZEROFILL]非常に小さな整数。符号付きの範囲は -128 〜 127。符号なしの範囲は 0 〜 255。
BIT , BOOL , BOOLEAN
いずれも TINYINT(1) のシノニム。 シノニム BOOLEAN はバージョン 4.1.0 で追加された。
ブール型の完全な処理は SQL-99 に基づいて導入される。
[
MySQL
::
MySQL
5.1 リファレンスマニュアル :: 10.1.1 数値タイプの概要]
http://dev.mysql.com/doc/refman/5.1/ja/numeric-type-overview.html
こっちは5.1の数値リファレンス。
あれ?bit(1)もtinyint(1)と同じなの?
またまたー。
最近、bit(1)だったら正しく真偽値持ってるような意図になるんじゃないの?って疑問視してたらこれだよ・・・。
調べてったらbooleanの検証があったのでご紹介。
[MySQL5.1のboolean型を検証 | 1000g]
http://1000g.5qk.jp/2010/11/15/mysql5-1%E3%81%AEboolean%E5%9E%8B%E3%82%92%E6%A4%9C%E8%A8%BC/
tinyint(1)と同じになって、
・NULL
・0(where句でcolumn = falseで引っかかる)
・1(where句でcolumn = trueで引っかかる)
・2〜127(true,falseで引っかからない)
が挿入出来るみたい。
認識に違いは無かった。
さて、bitはどうなんよ?ってことで試すことにした。
そもそも
Rails
で非対応の型どうすんの?って場合はこちらも参考に。
[
Rails
の Migration で
MySQL
の型を指定する | METAREAL]
http://www.metareal.org/2008/02/06/using-mysql-data-types-in-rails-migration/
class CreatePepsi < ActiveRecord::Migration
def self.up
create_table :pepsies do |t|
t.column :coke, :"CHAR(64)"
t.column :jolt, :SMALLINT
...
こんな感じにすると非対応の型でも出来るみたい。
ちょっと単純にいきたいので、まずは
MySQL
で直接作る。
CREATE TABLE bit_test(
id int(11),
bit1 bit(1),
bit64 bit(64)
);
PRIMARY KEYは?とか、ストレージエンジンは?とかは簡単な例って事で省略。
どうでもいいけれど、全部小文字で昔は書いてたけれど、
「命令文の
予約語
は大文字にして、変数やテーブル名、列名を小文字にするとプログラム上で見てて区別が付きやすい」
と前職の人が言っていて、確かにと納得して区別するようになった。
続いてデータ挿入。
INSERT INTO bit_test VALUES(0,0,0);
INSERT INTO bit_test VALUES(1,1,1);
INSERT INTO bit_test VALUES(2,2,2);ERROR 1406 (22001): Data too long for column 'bit1' at row 1
bit(1)だと、2を保存しようとしたらData too longになる。
これはカラムのデータ保存領域がちゃんと1bitになってるのかな?
そんなわけないか、バイト単位でしか保存されないのかな。
その辺内部構造までは理解が至らないものの、
tinyint(1)やbooleanと違って、
「2が保存できない」事を確認した。
SELECT * FROM bit_test WHERE bit1 = true;
SELECT * FROM bit_test WHERE bit1 = false;
SELECT * FROM bit_test WHERE bit64 = true;
SELECT * FROM bit_test WHERE bit64 = false;
これも思い通りの結果が返って、
真偽値で保存されていて、それ以外は保存出来ない手応えを得た。
適当に
Rails
のアプリケーションを新規作成。
mkdir bit_test_app
cd bit_test_app
rails bit_test
cd bit_testruby script/generate model BitTest
RAILS
_ROOT/config/database.ymlを開いて編集
development:
adapter: mysql
database: bit_test_dev
user: xxxxx
password: xxxxx
rake db:create 実行。
続いて
RAILS
_ROOT/db/に出来た
マイグレーション
ファイルを開いて編集
class CreateBitTests < ActiveRecord::Migration
def self.up
create_table :bit_tests do |t|
t.column :bit1, :"BIT(1)"
t.column :bit64, :"BIT(64)"
end def self.down
drop_table :bit_tests
end
と編集し、rake db:migrateを実行。
MySQL
のクライアントで、SHOW CREATE TABLE bit_tests;を実行して、bit型になっていることを確認。
mysql -uxxxxx -pxxxxx
USE bit_test_dev;
SHOW TABLES;
SHOW CREATE TABLE bit_tests;CREATE TABLE `bit_tests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bit1` bit(1) DEFAULT NULL,
`bit64` bit(64) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Rails
のコンソールを立ち上げる。
ruby script/console>> BitTest.create
=> #
>> BitTest.create(:bit1 => 1)
=> #
>> BitTest.create(:bit1 => 0)
=> #
>> BitTest.create(:bit1 => 3)
=> 激しくエラー。bit(1)に3を保存して、Data too longだと思う。
>> BitTest.create(:bit64 => 3)
=> # #bit(64)なら3は保存可能
>> BitTest.create(:bit1 => true)
=> #
>> BitTest.create(:bit1 => false)
>> require "pp"
=> []
>> pp Bittest.find(:all, :conditions => ["bit1 = ?" true])
=> nil
>> pp Bittest.find(:all, :conditions => ["bit1 = ?" 1])
=> nil
>> pp Bittest.find(:all, :conditions => ["bit1 = ?" false])
=> nil
いい感じ。でもStringが返ってるね。
>> Bittest.find(:first, :conditions => ["bit1 = ?" true]).bit1
"\001"
=> nil>> Bittest.find(:first, :conditions => ["bit1 = ?" true]).bit1.class
String
=> nil
非常にマッチする記事を見つけた。
[
MySQL
のBIT型 - LazyLoadLife]
http://d.hatena.ne.jp/babie/20080717/1216286789
unpackとかpackすれば、intに出来るとのこと。
bit(1)なら、true・falseに使えて2以上保存出来ない(エラーが起きる)し、
ちゃんと0/1,true/falseで検索も出来るので問題ないといえばないけれど、ややこしい。
仮に1000万レコードあったとして、
内部構造的に、tinyint(1)より容量が少なかったり、selectのパフォーマンスが良いなら使うのもいい気がした。
タイトルに入れたけど
enum
は普段使う事が無くて、最近目にしてるだけで書いただけでした。
正確にやりたければそれがいいと記事では見たけれど、普段使わないのでわからず!
以上、
Rails
における非対応カラムの作成と、
MySQL
・
Rails
におけるtinyint(1)、bool、boolean、bit(1)についてのまとめでした。