カテゴリー
SugiBlog Webエンジニアのためのお役立ちTips

MySQL GROUP BYとHAVING

MySQLではGROUP BYを使ってレコードをグループ化し、カラムの合計や最小値・最大値などを集計することができます。
集計した値をWHERE句の抽出条件指定に使用することはできません。
そんなときはHAVING句を使用します。

まずはサンプルのテーブルを用意しましょう。

CREATE TABLE `students` (
  `id` int(8) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  `class` int(4) NOT NULL,
  `score` int(4) NOT NULL,
  PRIMARY KEY (`id`)
);

サンプルデータを登録します。

INSERT INTO `students` VALUES
    (DEFAULT, '赤井', 1, 168),
    (DEFAULT, '井田', 2, 133),
    (DEFAULT, '宇野', 3, 167),
    (DEFAULT, '江崎', 1, 185),
    (DEFAULT, '奥本', 2, 142),
    (DEFAULT, '加藤', 3, 176),
    (DEFAULT, '菊池', 1, 159),
    (DEFAULT, '久保', 2, 181),
    (DEFAULT, '剣持', 3, 155);

classでグループ化し、scoreの合計を抽出してみましょう。

SELECT class, SUM(score) AS sum_score FROM `students`
GROUP BY class;

結果は次のようになります。

+-------+-----------+
| class | sum_score |
+-------+-----------+
|     1 |       512 |
|     2 |       456 |
|     3 |       498 |
+-------+-----------+

試しにWHERE句を使ってみましょう。

SELECT class, SUM(score) AS sum_score FROM `students`
WHERE sum_score > 500
GROUP BY class;

すると

ERROR 1054 (42S22): Unknown column 'sum_score' in 'where clause'

このようにエラーとなります。

それではHAVING句を使ってみましょう。

SELECT class, SUM(score) AS sum_score FROM `students`
GROUP BY class
HAVING sum_score > 500;

すると結果は次のようになります。

+-------+-----------+
| class | sum_score |
+-------+-----------+
|     1 |       512 |
+-------+-----------+

HAVING句による条件指定で絞り込みができています。

WHERE句はグループ化で集計される前、HAVING句はグループ化で集計された後のデータに対して条件を指定し絞り込むことができます。

91 views

XAMPPのshell 文字コードを変更

XAMPPのshellを使っていて、例えばmysqlコマンドでデータを確認したりする際、
文字コードがデフォルトShift_JISなのでDBの文字コードがUTF-8だったりすると文字化けして表示されてしまいます。
そんな時はshellの文字コードを変更しましょう。

コマンドは以下の通りです。
引数にコードページを指定します。

chcp 65001

コードページIDの一覧です。

932 shift_jis 日本語 シフトJIS(または、「shift-jis」や「x-sjis」など)
51932 euc-jp 日本語 EUC
50220 iso-2022-jp 日本語 JIS
50221 csISO2022JP 日本語 JIS(1バイトカタカナ可)
50222 iso-2022-jp 日本語 JIS(1バイトカタカナ可 – SO/SI)
65001 utf-8 UTF-8
87 views

MySQL GROUP BYのWITH ROLLUP修飾子とGROUPING関数

MySQLでGROUP BYを使って集計するときにWITH ROLLUPを使えば出力に集計行を追加することができます。

適当なサンプルデータを用意します。

mysql> create table t1 (a integer, b integer, c integer);
insert into t1 values (111,11,11),(222,22,22),(111,12,12),(222,23,23);

mysql> SELECT * FROM t1;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|  111 |   11 |   11 |
|  222 |   22 |   22 |
|  111 |   12 |   12 |
|  222 |   23 |   23 |
+------+------+------+
4 rows in set (0.000 sec)

WITH ROLLUP

まず単純にグループ化してみましょう。

mysql> SELECT a, b, SUM(c) as SUM FROM t1 GROUP BY a, b;
+------+------+------+
| a    | b    | SUM  |
+------+------+------+
|  111 |   11 |   11 |
|  111 |   12 |   12 |
|  222 |   22 |   22 |
|  222 |   23 |   23 |
+------+------+------+
4 rows in set (0.001 sec)

WITH ROLLUPを付けると出力結果に集計行が追加されます。

mysql> SELECT a, b, SUM(c) as SUM FROM t1 GROUP BY a, b WITH ROLLUP;
+------+------+------+
| a    | b    | SUM  |
+------+------+------+
|  111 |   11 |   11 |
|  111 |   12 |   12 |
|  111 | NULL |   23 |
|  222 |   22 |   22 |
|  222 |   23 |   23 |
|  222 | NULL |   45 |
| NULL | NULL |   68 |
+------+------+------+
7 rows in set (0.000 sec)

MySQL5.7以前のバージョンでは、GROUP BYは常にソートされます。
並び順を指定すると次のようになります。
このとき集計行に影響はありません。
続きを読む…»

106 views

XAMPPでPHPのモジュール版・CGI版切り替え

PHPにはモジュール版・CGI版の2種類があります。
主な違いは次の通りです。
モジュール版:ApacheのrootユーザーでPHPを実行・処理が速い
CGI版:ユーザー毎のPHP実行環境・セキュリティや安全性に優れている・モジュール版より遅い

XAMPPを使ってローカル環境で開発している場合、特に切り替えが必要なケースは稀かと思いますが、
参考までに切り替えの方法を記載しておきます。

httpd.conf

以下の行をコメント解除します。

#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

httpd-xampp.conf

モジュール用セットアップの記述をコメントアウト
※PHP7の場合の例です。

#
# PHP-Module setup
#
LoadFile "/xampp/php/php7ts.dll"
LoadFile "/xampp/php/libpq.dll"
LoadFile "/xampp/php/libsqlite3.dll"
LoadModule php7_module "/xampp/php/php7apache2_4.dll"

<FilesMatch "\.php$">
    SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch "\.phps$">
    SetHandler application/x-httpd-php-source
</FilesMatch>

CGI用セットアップの記述をコメント解除します。

#
# PHP-CGI setup
#
#<FilesMatch "\.php$">
#    SetHandler application/x-httpd-php-cgi
#</FilesMatch>
#<IfModule actions_module>
#    Action application/x-httpd-php-cgi "/php-cgi/php-cgi.exe"
#</IfModule>

PHPINFOを表示し、Server APIの欄を確認します。
こちらがApache 2.0 Handlerとなっていればモジュール版、
CGI/FastCGIになっていればCGI版で動作していることになります。

356 views

MySQLでカーソルを使って1行ずつ処理したい

ストアドプロシージャで1行ずつデータを処理したいときはカーソルを使って処理します。
以下、簡単な例をご紹介します。

-- 読み出した値を格納する変数を宣言
DECLARE currentId INT;
DECLARE currentColumnA VARCHAR(255);
DECLARE currentColumnB VARCHAR(255);

-- カーソルが最終行に達した判定するフラグ
DECLARE done INT DEFAULT FALSE;

-- カーソルを定義
DECLARE myCursor CURSOR FOR
SELECT id, columna, columnb FROM example;

-- カーソルが最終行に達したときの動作を制御
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

-- カーソルを開く
OPEN myCursor;

-- ループで1行ずつ処理
read_loop: LOOP
    -- カーソルから1行読み出し
    FETCH myCursor INTO currentId, currentColumnA, currentColumnB;

    -- カーソルからの読み出しが最後に達していればループを抜ける
    IF done THEN
        LEAVE read_loop;
    END IF;

    -- 読み出したデータを使用した処理等を書く

END LOOP;

-- カーソルを閉じる
CLOSE myCursor;
372 views