MySQLで詰まったところ

開発環境は、Windows 7 Professional(32bit) + MariaDB 10.1.25。

■シングルクォーテーションをエスケープする
SQLインジェクション対策で、シングルクォーテーションをエスケープしたい場合、『'』を『''』という風にもう1つシングルクォーテーションを追加する。『'こんにちは'』であれば、『''こんにちは''』となる。

参考サイト
SQLでは「'」をエスケープする際に「''」を使う


■selectで複数のテーブルからデータを取得する場合に、カラム名を指定する場合の省略の仕方
もしかしたら、こういう書き方もありなんじゃないかとやってみると、うまくできたのでメモしておく。プログラミングという論理の世界で生まれた問題を、直感で生まれた論理を試してみると、解決できるということが、自分の場合、たまにある。

select posts.*, users.imageurl from posts inner join users on posts.username = users.username;


■WHERE句の指定の仕方

# idが5のデータを取得する
select * from tablename where id = 5;
# idが5以外のデータを取得する - パターン1
select * from tablename where id <> 5;
# idが5以外のデータを取得する - パターン2
select * from tablename where id != 5;
# idが5より大きいデータを取得する
select * from tablename where id > 5;
# idが5以上のデータを取得する
select * from tablename where id >= 5;
# idが5より小さいデータを取得する
select * from tablename where id < 5;
# idが5以下のデータを取得する
select * from tablename where id <= 5;
# statusがonのデータを取得
select * from tablename where status = 'on';
# statusがoff以外のデータを取得 - パターン1
select * from tablename where status <> 'off';
# statusがoff以外のデータを取得 - パターン2
select * from tablename where status != 'off';


■乱数を作成する
【例】仮データを入れる際に用いる。

# 0~9までの乱数が発生
select floor(rand() * 10);
# 文字列の乱数(10桁文字列)
select substring(md5(rand()),1,10);
# 日付の乱数 - 2018年3月1日~3月31日まで
select add_date('2018-03-31',interval 31 * rand() day);

参考サイト
https://www.ilovex.co.jp/blog/system/mysql/mysql-9.html


■inner joinの使い時
・取得したテーブルに1対1の関係で別のテーブルからデータを取得して、連結させたい場合は、inner joinを用いる。
【例】投稿したある記事に対して、投稿したユーザーの情報を結合して表示したい場合


■left join/right joinの使い時
・ある条件に合致した時に別のテーブルデータからデータを取得したい場合は、left join/right joinを用いる。
【例】自分がお気に入りアイコンをクリックしたものだけ、アイコンの表示を変えたい場合など。


カラム名が被っている場合
as句を用いて、一時的に名前を変更することで、カラム名が被っていても使用することができる。

current_column_name as new_column_name;


■group byとorder byを併用したい場合どうするか?
・group byでユーザー名をまとめた、それぞれに対して、max関数を用いて、最大のものを抽出して、それを、サブクエリとしてwhere in 句に渡す。
・過程で分かったこととして、サブクエリの中でorder byは使うことができない。group byは使うことができる。
調べたところ、実行の順序は、group by→order byじゃないといけないみたいだ。
【例】各ユーザーの最新の投稿を1件だけ表示したい場合。

select * from posts where created in (select max(created) from posts group by user_id) order by id limit 20;

【例】過去1時間に検索されたキーワードから上位5件だけ取得したい場合

select search_keyword, count(search_keyword) as kensu from search where created > date_add(sysdate(),interval - 1 hour) group by search_keyword order by kensu desc limit 5;

参考リンク
MySQLでGROUP BYとORDER BYを同時に使用する場合に気をつけたいこと | 日記の間 | あかつきのお宿
サブクエリーでORDER BYは使えない - R42日記
group byはorder byより先に処理される。これ重要。 - Webtech Walker
MySQLコマンド・関数一覧(データベース)|ITリファレンス
翌月を取得する - MySQL 逆引きリファレンス


■ユーザー定義変数を使う
例えば、PHPから、変数$hogeを受け取って、その値をSQL文の変数に入れて、テーブルのデータとして追加したい場合、

<?php
$hoge = "test";
$sql = <<<"EOF"
select (@hoge := '$hoge') as hoge from posts;
"EOF";

?>

:=じゃなくて=だけだと、値が入らずに変わりに、NULLが入る。

参考リンク
MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.4 ユーザー定義変数
mysqlでユーザ定義変数をつかう - 眠すぎて明日が見えない
MySQLのユーザー変数