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

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は常にソートされます。
並び順を指定すると次のようになります。
このとき集計行に影響はありません。
続きを読む…»

270 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版で動作していることになります。

823 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;
539 views

MySQLトランザクションでROLLBACKが効かない

タイトルにもある通り、MySQLトランザクションにてROLLBACK(ロールバック)ができないケースがあります。
一連の処理を記述し、特定条件下やどこかで失敗した場合等に全てを元に戻せるということで非常に便利なROLLBACKですが、
ROLLBACKできないSQL文がトランザクションに含まれていた場合、ROLLBACK自体がエラーとなり元に戻らないことがあります。

ROLLBACKできないSQLの例
  • CREATE
  • DROP
  • ALTER
  • TRUNCATE
ROLLBACKできるSQL
  • INSERT
  • UPDATE
  • DELETE

但しこちらはMySQLに限ったお話ですので、他のDBの場合は要確認です。
他のDBではROLLBACKできる場合があります。

公式リファレンス
https://dev.mysql.com/doc/refman/8.0/ja/cannot-roll-back.html

745 views

gitコマンドで差分抽出とアーカイブ出力

gitを使ってソース管理し開発をしていて、差分ファイルをリリースするときのTipsです。

差分を抽出する

git diff [古いブランチ名]..[新しいブランチ名]
git diff [古いブランチ名] [新しいブランチ名]

ファイル名だけを列挙したいとき

git diff --name-only [古いブランチ名] [新しいブランチ名]

ファイル名のリストをテキストファイルにリダイレクトで書き出す

git diff --name-only [古いブランチ名]..[新しいブランチ名] >> diff.txt

ブランチをアーカイブ出力

git archive [ブランチ名] -o archive.zip

出力するディレクトリを指定

git archive --prefix=archive/ [ブランチ名] -o archive.zip

差分抽出とアーカイブ出力を組み合わせて、抽出した差分ファイルをアーカイブ出力

git archive --prefix=archive/ [新しいブランチ名] (git diff --name-only [古いブランチ名] [新しいブランチ名] --diff-filter=ACMR) -o diff.zip
フィルターの種類
A 追加
C コピー
M 変更
R リネーム
D 削除

小文字にすると逆になるので、以下のようにしても同じことになります。

git archive --prefix=archive/ [新しいブランチ名] (git diff --name-only [古いブランチ名] [新しいブランチ名] --diff-filter=d) -o diff.zip
2,030 views