ラベル mysql の投稿を表示しています。 すべての投稿を表示
ラベル mysql の投稿を表示しています。 すべての投稿を表示

2014年5月23日金曜日

MySQLのCollationを理解するためにまとめてみた。

MySQLのCollationを理解するためにまとめてみた。

Collation…

MySQL独特の仕様、Collationがあまりしっくりこなかったので理解するためにまとめてみました。

テーブルJOINしようとして、たまにCollationちげーよ!とか言われるアレです。

ERROR 1267 (HY000): Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='

Oh...

Collation とは?

直訳すると照合。

文字コード毎の照合順序を定義します。

大雑把に言ってしまうと。
MySQLは文字コードとソート順を持っていて、ソート順の部分がCollationとよばれている。(文字コードの部分はCharacter Set)

比較するときには文字コードだけでなくてCollationが一致するかどうかを比較する(順序が合わないと比較できない)。
ので、JOINしようとするとコレーっとなる。。。

Collation の意味

Collationの命名規則は,”文字コード_言語名_比較法”

source: MYSQL Collation | variable.jp [データベース,パフォーマンス,運用]

例えば cp932_japanese_ci のようなCollationの場合。
文字コード: cp932
言語名: japanese
比較法: ci
と、読める。

文字コード、言語名、比較法?

文字コード

ご存知、utf8とかcp932とかのcharacter setの事。

言語名

japaneseやthaiやgeneral、unicodeなどが入ります。
generalやunicodeはマルチリンガルの事(utf8にjapaneseはない)。

比較法

_ci、_cs、_bin のいずれか(で終わる)

_ci: 大文字と小文字が区別されない
_cs: 大文字と小文字が区別される
_bin: バイナリ

Collationの確認

MySQLで使用できるCollationを確認するには、show collationステートメントを実行する。

例: utf8のcollationを取得

mysql> show collation like 'utf8\_%';
+--------------------------+---------+-----+---------+----------+---------+
| Collation                | Charset | Id  | Default | Compiled | Sortlen |
+--------------------------+---------+-----+---------+----------+---------+
| utf8_general_ci          | utf8    |  33 | Yes     | Yes      |       1 |
| utf8_bin                 | utf8    |  83 |         | Yes      |       1 |
| utf8_unicode_ci          | utf8    | 192 |         | Yes      |       8 |
| utf8_icelandic_ci        | utf8    | 193 |         | Yes      |       8 |
| utf8_latvian_ci          | utf8    | 194 |         | Yes      |       8 |
| utf8_romanian_ci         | utf8    | 195 |         | Yes      |       8 |
| utf8_slovenian_ci        | utf8    | 196 |         | Yes      |       8 |
| utf8_polish_ci           | utf8    | 197 |         | Yes      |       8 |
| utf8_estonian_ci         | utf8    | 198 |         | Yes      |       8 |
| utf8_spanish_ci          | utf8    | 199 |         | Yes      |       8 |
| utf8_swedish_ci          | utf8    | 200 |         | Yes      |       8 |
| utf8_turkish_ci          | utf8    | 201 |         | Yes      |       8 |
| utf8_czech_ci            | utf8    | 202 |         | Yes      |       8 |
| utf8_danish_ci           | utf8    | 203 |         | Yes      |       8 |
| utf8_lithuanian_ci       | utf8    | 204 |         | Yes      |       8 |
| utf8_slovak_ci           | utf8    | 205 |         | Yes      |       8 |
| utf8_spanish2_ci         | utf8    | 206 |         | Yes      |       8 |
| utf8_roman_ci            | utf8    | 207 |         | Yes      |       8 |
| utf8_persian_ci          | utf8    | 208 |         | Yes      |       8 |
| utf8_esperanto_ci        | utf8    | 209 |         | Yes      |       8 |
| utf8_hungarian_ci        | utf8    | 210 |         | Yes      |       8 |
| utf8_sinhala_ci          | utf8    | 211 |         | Yes      |       8 |
| utf8_german2_ci          | utf8    | 212 |         | Yes      |       8 |
| utf8_croatian_ci         | utf8    | 213 |         | Yes      |       8 |
| utf8_unicode_520_ci      | utf8    | 214 |         | Yes      |       8 |
| utf8_vietnamese_ci       | utf8    | 215 |         | Yes      |       8 |
| utf8_general_mysql500_ci | utf8    | 223 |         | Yes      |       1 |
+--------------------------+---------+-----+---------+----------+---------+

※1行目と3行目に注目。utf8_general_ciがutf8のデフォルトCollationになっている。が。Railsでは通常utf8_unicode_ciが使用される。
で。悲劇が起きる。。。

Column の Collation を確認

ColumnのCollationを確認するには、show full columns from tableステートメントを実行する。

例: itemsテーブル(項目)のCollationを確認する

mysql> show full columns from items;
+-------------------+--------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
| Field             | Type         | Collation       | Null | Key | Default | Extra          | Privileges                      | Comment |
+-------------------+--------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+
| id                | int(11)      | NULL            | NO   | PRI | NULL    | auto_increment | select,insert,update,references |         |
| code              | varchar(255) | utf8_unicode_ci | YES  | UNI | NULL    |                | select,insert,update,references |         |
| name              | varchar(255) | utf8_unicode_ci | YES  |     | NULL    |                | select,insert,update,references |         |
+-------------------+--------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+

※intにはCollationがないですね

utf8_general_ciとutf8_unicode_ciの使い分け

unicode の方はあいまいな照合が可能です。全角、半角、大文字、小文字を無視して一致するものを検索できます。
たとえば、検索文字に‘MySQL’を指定した時と、‘mysql’を指定した時の検索結果は同じになります。

general の方はその逆で、厳密に違いとして認識され先の例の検索結果は異なります。

どちらも項目の用途によって使い分けるのが、あるべき姿なのでは無いかと思います。

※余談ですがデフォルトで全項目unicodeを選択されるのはRailsぽいなーと思いました。id(int)はcollation関係ないですもんね。

JOIN !

で。utf8_general_ciとutf8_unicode_ciはCollationが違いますが、そもそも文字コードは同じutf8ですので、Collationを指定してやることで比較が(もちろんJOINも)できるようになります。

例: Collation を指定して JOIN する (collate句を使います)

select * from table_a a
  inner join table_b b
  on a.code = b.code collate utf8_general_ci  -- ココで collate してる

まとめ

理解できるとなかなかCollationも便利なように思えてきました。

最後のJOINのように collete句 を使う場合、table_b.code のindexって効かなくなるのかな…?
誰か詳しい方がおられましたら教えていただきたいデス。


参考:

MySQL :: MySQL 5.1 リファレンスマニュアル :: 9.2 MySQLにおけるキャラクタセットおよび照合順序

MYSQL Collation | variable.jp [データベース,パフォーマンス,運用]

【MySQL】大文字小文字、全角半角区別しないでマッチする検索をしたい at softelメモ


Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2014年4月16日水曜日

MySQLでsplit的な事をしたい時

MySQLでsplit的な事をしたい時

Splitがしたい

設計上良くないとは思いますが。。。
どうしてもしたい時ってありますよね。。。
例えば郵便番号や電話番号をハイフン毎にカラムを分けて取得したい場合など。

いっぱつでできません。

split関数のようなものはありませんので、関数を組み合わせて自力で分割してやる必要があります。

汎用例

replace(substring(substring_index(${対象項目}, ${区切り文字}, ${対象の位置}), char_length(substring_index(${対象項目}, ${区切り文字}, ${対象の位置} - 1)) + 1), ${区切り文字}, '')

-- 長いな...

具体例: 電話番号 000-000-0000 を3つに分割する
※例はあえて同じ 000 が登場するようにしています

-- 1項目目取得
select replace(substring(substring_index('000-000-0000', '-', 1), char_length(substring_index('000-000-0000', '-', 1 - 1)) + 1), '-', '');
-- > 000

-- 2項目目取得(対象の位置を2に変えた)
select replace(substring(substring_index('000-000-0000', '-', 2), char_length(substring_index('000-000-0000', '-', 2 - 1)) + 1), '-', '');
-- > 000

-- 3項目目取得(対象の位置を3に変えた)
select replace(substring(substring_index('000-000-0000', '-', 3), char_length(substring_index('000-000-0000', '-', 3 - 1)) + 1), '-', '');
-- > 0000

-- 4項目目取得(対象の位置を4に変えた)
select replace(substring(substring_index('000-000-0000', '-', 4), char_length(substring_index('000-000-0000', '-', 4 - 1)) + 1), '-', '');
-- > (なし)

日本語でおk

-- 項目2をとりたい
select replace(substring(substring_index('項目1|項目2|項目3', '|', 2), char_length(substring_index('項目1|項目2|項目3', '|', 2 - 1)) + 1), '|', '');
-- > 項目2

まとめ

すごくめんどくさいので、ちゃんと設計しましょう。
どうしてもダメな場合は汎用例で対応しよう。
Functionをつくったりなんかすると便利かもしれないですね。
でもやっぱり、ちゃんと設計しましょう。

参考

MySQL :: MySQL 5.0 Reference Manual :: 12.5 String Functions / http://dev.mysql.com/doc/refman/5.0/en/string-functions.html

まんなかくらいにある ## Split delimited strings が大変参考になりました。


Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年11月20日水曜日

homebrew で mysql をインストール

ハマったのでメモ

インストール

brew install mysql

オーナーチェンジ

エラーがでる場合は以下のコマンドを実行

sudo chown -R _mysql:_mysql /usr/local/var/mysql

エラーの例:

ERROR! The server quit without updating PID file (/usr/local/var/mysql/xxx.local.pid).

パスワードの設定

SET PASSWORD FOR root@localhost=PASSWORD('hoge');

Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年11月14日木曜日

MySQLで更新日時を自動的に設定する

MySQLで更新日時を自動的に設定する

MySQLではTIMESTAMP型を使うと更新日時を自動で更新してくれるようです。

以下の様な感じで試してみました。

  • TIMESTAMP型カラムを持つテーブルを作成
  • TIMESTAMP型カラムにnullでデータを挿入
    • 更新日時が設定されているか確認
  • データの更新
    • 更新日時が再設定されているか確認

TIMESTAMP 型カラムを持つテーブルを作成

※ 型指定以外はなにも付けていません

mysql> CREATE TABLE `tt_test` (
    ->    `ID` int AUTO_INCREMENT NOT NULL
    ->   ,`VALUE` varchar(10) NULL
    ->   ,`LAST_MOD` TIMESTAMP
    ->   ,CONSTRAINT PK_ID  PRIMARY KEY (ID)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> desc tt_test;
+----------+-------------+------+-----+-------------------+-----------------------------+
| Field    | Type        | Null | Key | Default           | Extra                       |
+----------+-------------+------+-----+-------------------+-----------------------------+
| ID       | int(11)     | NO   | PRI | NULL              | auto_increment              |
| VALUE    | varchar(10) | YES  |     | NULL              |                             |
| LAST_MOD | timestamp   | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+----------+-------------+------+-----+-------------------+-----------------------------+
3 rows in set (0.01 sec)

Default と Extra が勝手に設定される仕様のようです。

まずは、データを挿入してみます。

mysql> insert into tt_test values (null, 'val1', null);
Query OK, 1 row affected (0.01 sec)

mysql> insert into tt_test values (null, 'val2', null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt_test;
+----+-------+---------------------+
| ID | VALUE | LAST_MOD            |
+----+-------+---------------------+
|  1 | val1  | 2013-11-13 17:48:14 |
|  2 | val2  | 2013-11-13 17:48:15 |
+----+-------+---------------------+
2 rows in set (0.00 sec)

おお。作成日時が自動的に設定されました。

次に、データを更新してみます。

mysql> update tt_test set value = 'val3' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from tt_test;
+----+-------+---------------------+
| ID | VALUE | LAST_MOD            |
+----+-------+---------------------+
|  1 | val3  | 2013-11-13 17:48:19 |
|  2 | val2  | 2013-11-13 17:48:15 |
+----+-------+---------------------+
2 rows in set (0.00 sec)

更新されていますね。

何も考えずに(?)TIMESTAMP型を使用すると、上記のような動きをします。

本記事の内容には下記サイトを参考にさせていただきました。

デフォルト値の設定(DEFAULT) - テーブルの作成 - MySQLの使い方

Enjoy!


Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年10月17日木曜日

Oracle でシステム日付を文字列で取得

よくやるのでメモ。

select
 to_char(SYSTIMESTAMP,'yyyy/mm/dd hh24:mi:ss')
from dual;

ちなみに、MySQLの場合は

select DATE_FORMAT(now(),'%Y/%m/%d %k:%i:%s');

参考:

ORACLE/オラクルSQLリファレンス(SYSDATE/SYSTIMESTAMP)

SYSDATE、SYSTIMESTAMP - オラクル・Oracle SQL 関数リファレンス

MySQL では、sysdate() ではなく、now()を使うのが無難かも

SQL 日付、時刻の取得、フォーマット変更(MySQL、PostgreSQL、ORACLE)


Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年10月12日土曜日

Oracleでいうたらnvlやね

MySQLでのnull変換にはifnull関数を使用します。

ifnull(null_column, 'NULLの場合はこの値')

以下に例をいくつか挙げます。

mysql> select ifnull(null, 'NULLやで!');
+-------------------------------+
| ifnull(null, 'NULLやで!')    |
+-------------------------------+
| NULLやで!                    |
+-------------------------------+
1 row in set (0.01 sec)

mysql> select ifnull('x', 'NULLやで!');
+------------------------------+
| ifnull('x', 'NULLやで!')    |
+------------------------------+
| x                            |
+------------------------------+
1 row in set (0.00 sec)

mysql> select ifnull(0, 'NULLやで!');
+----------------------------+
| ifnull(0, 'NULLやで!')    |
+----------------------------+
| 0                          |
+----------------------------+
1 row in set (0.00 sec)

mysql> select ifnull(1/0, 'NULLやで!');
+------------------------------+
| ifnull(1/0, 'NULLやで!')    |
+------------------------------+
| NULLやで!                   |
+------------------------------+
1 row in set (0.01 sec)

ちなみに、こんなことはできませんのであしからず。 (引数は2つのみ)

mysql> select ifnull('x', 'NULLやで!', 'NULLちゃうで!');
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'ifnull'

mysql> select ifnull('x');
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'ifnull'

enjoy!


Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年10月8日火曜日

MySQLで ls などのコマンドをたたく

忘れそうなのでメモ。

MySQLのコンソールで、コマンドを叩く時は以下のようにします。
例: lsコマンドを実行

¥! ls

¥!とlsの間にはスペースが必要です。

けっこう回りくどいな。

ちなみに、oracleの場合は

!ls

だけなのでかなりシンプルです。

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年8月28日水曜日

MySQLでテーブル指定してダンプをとる

よく忘れるのでメモ

gz でダンプ(テーブルは複数指定可能)

mysqldump --user=xxx_user --password=xxx_password xxx_dbname xxx_tablename | gzip > mysql-backup-`date +%Y%m%d-%H%M%S`-xxx_tablename.sql.gz

gz しない場合

mysqldump --user=xxx_user --password=xxx_password xxx_dbname xxx_tablename > mysql-backup-`date +%Y%m%d-%H%M%S`-xxx_tablename.sql

Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly

2013年8月2日金曜日

Reverse Engineer... on MySQL Workbench

MySQL Workbench の便利機能

どうやら、既存のDBからテーブル定義をロードしてくれるようなので、試してみた。

しかし。

変なエラーがでた

Error: Cannot load from mysql.proc. The table is probably corrupted

んー。ナンノコッチャですが。

ぐぐってみるとなんとなく。homebrew でいれっぱ状態なのが問題なよう。

$ sudo mysql_upgrade -uroot -p

で問題なくupgradeが終わるとエラーが発生しなくなりました。

ちなみにupgrade後のMySQLバージョンはこれです。

$ mysql --version
mysql  Ver 14.14 Distrib 5.6.12, for osx10.8 (x86_64) using  EditLine wrapper

さっそく

試してみたけど、便利ですね。 いっこずつ手で入れるとかありえないっす。

Written with StackEdit.

  • この記事をシェアする

  • このエントリーをはてなブックマークに追加
  • このブログの更新をチェックする

  • follow us in feedly