この広告は、90日以上更新していないブログに表示しています。
以前,MySQL (正確にはMariaDB) を使った際,いろいろはまったので記載します.
使ったバージョンが古い(MariaDB 10.1.37,MySQL 5.7くらいに相当)なので,最新版では治っているところもいくつかあります.
これはよく言われていることですが,sql_modeがデフォルトでは変な値が入ったりエラーになって欲しいところがスルーされたりしてまずいので,適切なsql_modeを設定します.
第18回 MySQL5.7のデフォルトのSQLモードを確認してみる:MySQL道普請便り|gihyo.jp … 技術評論社
MySQLのSQLモードをstrictモードで設定する。 - Qiita
ただ,MySQL 5.7以降はデフォルト設定が改善されたようです.(でも確認すべきですが)
MySQL :: MySQL 8.0 Reference Manual :: 5.1.11 Server SQL Modes
GROUP_CONCATのバイト数の制限GROUP_CONCAT関数の結果の長さにはバイト数の制限(デフォルトで1024バイト)があり,超えるとGeneral error: 1260 Row 49 was cut by GROUP_CONCAT()などとエラーが出ます.
MySQL "Row 30153 was cut by GROUP_CONCAT()" error - Stack Overflow
解決策としては,SET group_concat_max_len=15000;などと設定を変更します.
これはよく調べていないですが,整数型を計算してビューの表示結果が小数になるときに,小数点以下の桁数をMySQLが勝手に設定するようです(結果がDecimal型になる).
cast(<小数を返す式> as double)みたいにしたら,桁数が増えました.
それでこの警告はビューを他のビューから参照するときには表示されず,create table select * from <ビュー名>とするときに警告が表示されました.
MySQLでは,0で除算するとNULLを返します.
本来ならば、sql_modeにtraditional,ERROR_FOR_DIVISION_BY_ZERO を指定していればエラーになるはずだが、警告どまりです.
2005年にバグ報告があるが、使っていたバージョンではまだ治っていませんでした.最新版では治っているかもしれません.
あと,これはMySQLはあまり関係ないですが,割り算するときはnullif関数を使うのが定石のようです.(分子が0のときは分枝をNULLにして,結果をNULLにする)
create table select * from ...で生成されるテーブルのカラムの型はどうなる?基本的にはselectの結果のカラムや式から決まるようですが,公式ドキュメントに詳しくは書いていないようです.
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.1.17.1 CREATE TABLE ... SELECT 構文
ちなみに,日本語版ドキュメントで「リトレインされる属性は ...」とあるのは,原文では「Retrained attributes are ...」となっていて,「Retrained」は「Retained」のタイポっぽいです.つまり,「保持される属性は...」という意味です.
ということで,NULLやNOT NULL,DEFAULTなどは生成されるテーブルでも保持されます.
DB名やテーブル名は,WindowsのMySQLでは区別しないが,Unix系のMySQLでは区別します.ただし,Unix系でも同一ステートメントで別のcaseでの表記を混在できません.
しかし,カラム名はどの環境でも区別しません(なんだこの仕様は...).
また,lower_case_table_namesシステム変数で挙動が変わります.
MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.2.2 識別子の大文字と小文字の区別
MySQLにおける大文字と小文字の区別 | KentaKomai Blog
設定項目がいくつもあったり,utf8 と utf8mb4があったりして注意です.
現時点では,基本的にutf8mb4にしておくのが良いようです.(utf8だと絵文字とかが化ける)
ただし,utf8mb4だとバイト数が多くなるので,キーの指定時にキーが長すぎというエラーになることがあるので調整が必要です.
mysqlで文字コードをutf8にセットする - Qiita
有名なやつですね.寿司とビールの絵文字が比較で同一視されるみたいなやつです.
Collation (照合順序) を良いように設定します.
Collationによって,アルファベットの大文字小文字を区別するかも気をつける必要があります.
Collation指定のレベル (サーバ単位, DB単位, テーブル単位, カラム単位) に関しても注意点があったりします.
MySQLのCollationはどのように決まるか。そして、3つの落とし穴。 - なからなLife
create tableで指定する他に,whereやjoinで適宜指定することもできます.
MySQL :: MySQL 5.6 リファレンスマニュアル :: 10.1.7.2 SQL ステートメントでの COLLATE の使用
特にjoinでは,大文字小文字を区別しなくて意図したようにjoinできなかったみたいなのにならないように注意です.
datetime型はタイムゾーンの影響は受けないです.
timestamp型はタイムゾーンの影響は受けます.内部はUTCで保持しているためです.
タイムゾーンによって,NOW()やSYSDATE()が返す日付や値の表現が変わります.
mysqlでタイムゾーンをキチンと扱ってみる - tocsatoの備忘録
mysqlでnow()を使用するためにタイムゾーンを設定する – 猫のプロトコル
これはMariaDB特有だった気がします.
MariaDBでは、ストアドファンクションは,create function時のsql_modeで実行されます.Charsetもcreate function時のものがデフォルトで使われます.
Prosedureも同じく,create時のものが使われます.
CREATE FUNCTION - MariaDB Knowledge Base
以下公式ドキュメントから引用です.
MariaDB stores the SQL_MODE system variable setting that is in effect at the time a routine is created, and always executes the routine with this setting in force, regardless of the server SQL mode in effect when the routine is invoked.
DELETE table_name FROM table_name LEFT JOIN ..のように,DELETEの直後にテーブル名を指定します.
You can't specify target table 'HOGE' for update in FROM clauseエラーたとえば,以下ではエラーが出ます.
DELETE HOGE FROM HOGEWHERE HOGE.id NOT IN (SELECT MIN(id) FROM HOGE GROUP BY col1)
以下のようにselect * from ( .. ) as pを噛ませると成功します.
DELETE FROM HOGEWHERE HOGE.id NOT IN ( SELECT * FROM ( SELECT MIN(id) FROM HOGE GROUP BY col1 ) AS p )
DELETEとかUPDATE文において,更新対象のテーブルをFROMに指定したサブクエリはそのままでは実行できないです.
mysql - You can't specify target table 'NAME' for update in FROM clause - Stack Overflow
You can't specify target table 'table_name' for update in FROM clause - MySQL
General error: 1093 Table 'HOGE' is specified twice, both as a target for 'UPDATE' and as a separate source for dataこれも上記のDELETEと同様に(SELECT * FROM xxx) as tみたいにすれば成功します.
mysql_config_editor公式の推奨は、mysql_config_editorを使用して、暗号化されたパスワードファイルを生成して保存することです.
MySQL :: MySQL 8.0 Reference Manual :: 6.1.2.1 End-User Guidelines for Password Security
mysql_config_editor の罠 | Netassist Blog
しかし、mysql_config_editorはMariaDBではサポートしていないです.(mysql_config_editor compatibility - MariaDB Knowledge Base )
また,mysql_config_editorを使うのは,「特定のホストからはパスワード無しでログインできるようにしているのと同じ」なのは留意する必要があります.(security - Where store password / login-path in MariaDB (equivalent for mysql-config-editor)? - Stack Overflow )
~/.my.confに記載mysqlコマンドでの接続時に,mysql --defaults-file=<conf path>のようにオプションで指定します.
.my.cnfは、chmod 600のように,所有ユーザ以外は読み書きできないようにしておきます.
当然ながら,このファイルには,ファイルがあるホストからしかアクセスできないので安全です.
MariaDBではこれがよさそうです.
SO_PEERCREDSO_PEERCREDというオプションを使う手もあるようですが,全然調べていないです.
DROP CONSTRAINT IF EXISTS制約があるときのみDROPする機能はMySQLには無いので,自分でプロシージャを作るなりする必要があります.
mysql - Drop foreign key only if it exists - Stack Overflow
/*!00000形式のコメントは?特定のバージョン以降のMySQLで実行されるコマンドです.
互換性のため,他のDBMSで実行されないようにということでしょう.
MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.6 コメントの構文
ALTER TABLE table_a DISABLE KEYSは効かないMyISAM でないと効かないらしいです.オプションの問題なのか,mysqldumpした結果に入っており,リストア時にwarningは出るということがありました.
なお,どちらにしてもmysqldumpの結果のSQLでは,FOREIGN_KEY_CHECKS=0としているので,外部キーは無効になります.
1レコードのサイズの上限は65,535バイトです. (a maximum row size limit of 65,535 bytes)
VARCHARは制限に含まれます.TEXTなどは制限外です.
What is the MySQL VARCHAR max size? - Stack Overflow
代わりにNULLを渡すなりするしかないです.
Writing optional parameters within stored procedures in MySQL? - Stack Overflow
hoge = (select fuga from ...)とかの場合です.
enumは追加情報を付加できないし、変更が大変なので、絶対に変わらないようなもの (male/female, child/adult) に限るべき.
基本的には別テーブルにしてJOINが良さそうです.
database design - MySQL ENUM type vs join tables - Stack Overflow
(変数ではなく)定数を定義する構文やnamespaceは無いです.(postgresqlでもそうです)
回避策としては,
MySql const values - Stack Overflow
MySQL :: How to define a constant that could be used across several procedures?
show tablesでテーブル一覧を取得すると,ビューも含まれるshow full tables where Table_Type = 'BASE TABLE'とします.
mysql - How to get only tables, not views using SHOW TABLES? - Stack Overflow
ON DELETE CASCADE外部キーで参照されてるテーブルは,ON DELETECASCADEしてもtruncateでエラーになります.
truncateはそういうチェックをしないで高速に削除するものなので当然といえば当然ですが.
SET FOREIGN_KEY_CHECKS=0;とします.
ただし、その後SET FOREIGN_KEY_CHECKS=1にしても違反データはそのままになります
違反がないことを確認するには、ツールなどで確認する必要があります.
mysql - Finding Damage Done by FOREIGN_KEY_CHECKS=0 - Database Administrators Stack Exchange
errno: 150 "Foreign key constraint is incorrectly formed"外部キー作成時のエラーですが,原因はいろいろあります.
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPが付きます.ALTER TABLE <table name> ALTER COLUMN <timestamp column name> DROP DEFAULT;とします.ON UPDATE ...を付けても,テーブルの値が変わらないとtimestampの値が更新されません.explicit_defaults_for_timestamp=ONMySQL5.6.5以前では,DATETIME型だと初期値、更新値にDEFAULT CURRENT_TIMESTAMPを設定できないです.
代わりに,RIGHTとLEFTをしてUNIONします.
なお,CROSS JOINはできます.
php - Why does MySQL report a syntax error on FULL OUTER JOIN? - Stack Overflow
create table as select ...でtimestamp型があるときにError Code: 1067. Invalid default value for 'ts'とエラーが出るバグです.
MySQL Bugs: #83704: Invalid default value for TIMESTAMP DEFAULT CURRENT_TIMESTAMP column
引用すると,
When using:- a timestamp column with default-create table .. as select * from (...)- a sub query (2 "select" incascade)-SET SESSION sql_mode = 'NO_ZERO_DATE';
=>Error Code: 1067. Invalid default value for 'ts'
ということです.
CREATE TABLE TEST_2 AS SELECT * FROM (SELECT NOW() AS a) wrap;とすると再現します.
一時的にNO_ZERO_DATEを無効化することで回避します.
FlexviewというものがMariaDBにあるが、DBエンジンネイティブなものではないようです. (update イベントでテンポラリテーブル更新処理とかしないといけない)
なお、クエリキャッシュというものがあったが、新しいバージョンでは削除されました.アプリケーション側でなんとかしろということのようです.
MySQL 8.0 から実装されました.
MySQL 8.0.16で実装されました.
日々の覚書: MySQL 8.0.16にCHECK制約が来て、NOT ENFORCEDなんてものまでついてきた
それ以前のバージョンでCheck制約をエミュレーションする方法:
CHECK制約をエミュレートする新旧の方法とドメイン (MySQL Server Blogより) | Yakst
デフォルトでは,CAST('a' as integer)は0を返します.
エラーを検知したいときは,正規表現などで、変換可能であることを確認するのが良さそうです.
その他ヤバイ自動変換については下記にまとまっています.
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。