重複を除いたデータ件数 COUNT( DISTINCT XXX )
サンプルデータベース sales
id
animal_id
shop_id
1
1
1
2
1
2
3
1
2
4
2
2
5
3
1
6
4
3
7
4
1
8
5
2
9
6
2
10
6
3
重複を除いたanimal_idの件数を数える。
SELECT count(DISTINCT animal_id) FROM sales WHERE 1
結果 → 6
GROUP BY とCOUNTの組み合わせでも重複を除いた件数を取得できるが、こちらがスマートである。
ページネーションとLIMIT
一覧画面などでページネーションを使う場面はよくある。
ページネーションで関係してくる情報はレコードの取得位置と取得数である。
取得位置と取得数が分かれば、SQLのLIMITで必要なデータを取ってこれる。
SQLでのLIMITの使い方は以下のとおりである。
SELECT * FROM tests LIMIT 取得位置,取得数 ;
※取得位置は0から始まる行の番号である。
以下のような記述方法もある。
SELECT * FROM tests LIMIT 取得数 OFFSET 取得位置;
日付の日の部分で検索
date型のフィールドに対して年、月、日を部分的に指定して検索できる。
日(3日)で絞り込む場合
SELECT * FROM `nekos` WHERE DATE_FORMAT(test_date, '%d')=3;
年月(2014年4月)で絞込場合
SELECT * FROM `nekos` WHERE DATE_FORMAT(test_date, '%Y-%m')='2014-04';
phpMyAdminの認証ぎれ対策
phpMyAdminをしばらく操作しないでいると、
「1440 秒以上操作をしませんでした。ログインし直してください。」
というメッセージが出て、再ログインがせままれる。
有効期間を1440秒以上に増やしたい場合、以下の操作をする。
phpMyAdminにログイン
ホーム→設定→機能
「ログインクッキーの有効期間」を増やす。
1つのテーブルでツリー構造データを扱う
parent_idと自分自身をLEFT JOINすることによりツリー構造データを再現する。
サンプルデータ:1行目は親要素で残りは子要素
id
title
category_id1
parent_id
1028
テスト・タイトル
99
NULL
1029
テスト2
99
1028
1030
テスト3
99
1028
1031
テスト4
99
1028
1032
テスト5
99
1028
ツリー構造データとして取得するSQL
SELECT C.id,C.title,C.parent_id,P.title
FROM recs AS C
LEFT JOIN recs AS P ON C.parent_id=P.id
WHERE
C.category_id1=99
ツリー構造データ。一覧に親要素のタイトルが付加されている。
id
title
parent_id
title
1028
テスト・タイトル
NULL
NULL
1029
テスト2
1028
テスト・タイトル
1030
テスト3
1028
テスト・タイトル
1031
テスト4
1028
テスト・タイトル
1032
テスト5
1028
テスト・タイトル
新規追加と更新を自動判別 | ON DUPLICATE KEY UPDATE
「 ON DUPLICATE KEY UPDATE 」を使うと、通常はINSERTによる行追加だが、プライマリーキーやユニーク成約で重複する場合はUPDATEによる行更新となる。
INSERT INTO animals (id, name,price)
VALUES (9, 'キノボリトカゲ', 9000)
ON DUPLICATE KEY UPDATE id=9, name='キノボリトカゲ', price=9100
id
name
price
6
オオヒラタクワガタ
3500
7
リュウキュウノコギリクワガタ
800
8
タテヅノマルバネクワガタ
10000
9
キノボリトカゲ
9100
複数行のデータをコンマで連結して1行にまとめる | GROUP_CONCAT
◇サンプルデータ nekosテーブル
id
val1
text1
1
1
neko
2
2
kani
4
4
buta
5
3
yagi
6
3
ari
7
3
tori
8
3
kame
9
111
10
123
PANDA
11
124
risu
◇サンプル:基本
SELECT GROUP_CONCAT (id SEPARATOR ', ') FROM nekos
GROUP_CONCAT(id SEPARATOR ', ')
1, 2, 4, 5, 6, 7, 8, 9, 10, 11
◇サンプル:応用
SELECT
GROUP_CONCAT(id SEPARATOR ',') AS ids
,GROUP_CONCAT(text1 SEPARATOR ',') AS texts
FROM nekos
GROUP BY val1
ids
texts
1
neko
2
kani
8,7,6,5
kame,tori,ari,yagi
4
buta
9
10
PANDA
11
risu
◇サンプル:応用2:コンマで連結した文字を並べる
SELECT
GROUP_CONCAT(id SEPARATOR ',') AS ids
,GROUP_CONCAT(text1 order by text1 SEPARATOR ',') AS texts
FROM nekos
GROUP BY val1
ids
texts
1
neko
2
kani
8,7,6,5
ari,kame,tori,yagi
4
buta
9
10
PANDA
11
risu
参考
フィールドを連結して検索 | CONCAT
SELECT * FROM nekos WHERE CONCAT( neko_val, neko_name ,neko_date) LIKE '%2014%'
3つのフィールドであるneko_val,neko_name,neko_dateを連結して一つの文字列にし、その文字列に対してLIKE条件を指定している。
ただこの方法は問題もあり、neko_val,neko_name,neko_dateのいずれかひとつだけでもNULLがあると、連結文字列もNULLとなってしまい検索できなくなる。
この場合、IFNULLを用いることで対処できる。
SELECT * FROM nekos WHERE CONCAT( IFNULL (neko_val, ''), IFNULL(neko_name, '') ,IFNULL(neko_date), '') LIKE '%2014%'
2018-8-29 | 2018-8-30
行の作成日時と更新日時を自動化する
created_at,create_atなどの日時系フィールドの型ですがtimestamp型でなくdatetime型がよい。
理由は以下の通り。
timestamp型には2038年問題があります。
何かのタイミングでUTC/協定世界時とJST/日本標準時の間で変換されてしまうことがあります。
Laravelのマイグレーションなどでtimestamp型が原因で処理中断というケースがありました。
datetime型でもデフォルトで現在日時をセットする条件を付与できますので、こちらを採用するほうが無難です。
CREATE TABLE animals (
id INT(10),
name VARCHAR(10),
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
)
旧式
※未推奨
作成日`created`フィールドを追加するSQLの例
ALTER TABLE `tests` ADD `created` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時'
更新日`modified`フィールドを追加するSQLの例
ALTER TABLE `tests` ADD `modified` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時'
注意:CURRENT_TIMESTAMPは1つのカラムにしか適用できないため、上記の2種類を同時に定義することはできない。(どちらか片方のみ)
トリガーを使う方法があるらしい。
他のテーブルのSELECT結果をUPDATEする
下記の例では動物テーブルのspeedに魚テーブルのswim_speedをまとめてセットする例。
テーブルの紐づけ条件はWHERE部分で行う。
UPDATE
animals,
fishs
SET
animals.speed = fishs.swim_speed
WHERE
animals.fish_id = fishs.id
月別で集計するSQL
日を月別で集計するフィールドの例。
売上sale_amountを月毎に集計する。件数もついでに取得。
2015年で絞込。
test_dateはyyyy-mm-dd型の日付フィールド
SELECT
DATE_FORMAT(test_date, '%Y-%m') as test_ym,
COUNT(id) as count,
SUM(sale_amount) as sum_sale_amount,
FROM
shops
WHERE
DATE_FORMAT(test_date, '%Y') = '2015'
GROUP BY
DATE_FORMAT(test_date, '%Y-%m')
ホーム
プログラミングの覚書目次
MySQLの覚書目次