mysql – こみなのメモ帳 / 趣味と実益のネタ帳 Tue, 05 Aug 2025 14:40:20 +0000 ja hourly 1 https://wordpress.org/?v=6.1.1 H2DBのLinked Tablesについて調べてみた /archives/1670/ /archives/1670/#respond Tue, 05 Aug 2025 14:40:20 +0000 https://www.komina.info/?p=1670 H2DBにはLinked Tablesという機能があります。外部テーブル(ほかのDB)へのテーブルリンクを作成して、あたかも H2DB 内に存在するテーブルかのように扱う機能です。

JDBCドライバで接続できるDBであれば、以下のようなコマンドで利用可能です。

CREATE LINKED TABLE LINK('org.h2.Driver', 'jdbc:h2:./test2', 'sa', 'sa', 'TEST');

社内に MySQL PostgreSQL などいろんなDBサーバが乱立しているようなときに使ったら便利そう、ということで調べてみることにしました。

環境構築

docker-composeを使ってお試し環境を作ってみました。h2db + mysql + postgresql な環境です。githubに一式を公開してあります。

https://github.com/komina77/h2db

git clone https://github.com/komina77/h2db.git
cd LinkedTables
docker-compose up -d

サンプルデータは MySQL の公式サイトにあるサンプルデータworld)を利用させてもらうことにします。これを mysqlpostgresql の両方の初期データとしてインストールすることにします。(postgresql へはそのままの文法では食わせることはできなかったので少し書き換えています)

city, country, countryLanguage の3つのテーブルから構成されるデータベースになります。

MySQLを参照してみる

実はH2DBのサーバに内蔵されているWeb管理画面はH2DB以外のDBにも接続できますので、これを利用してみたいと思います。

ホストOS上のブラウザで、http://localhost:8082/ を開き、保存済設定の中から「Generic MySQL」を選びます。ドライバクラスなどのデフォルト設定が表示されるので、JDBC URLやユーザ名、パスワード(mysql/mysql)を入力します。接続テストが通れば成功です。

PostgreSQLを参照してみる

同様に PostgreSQL のデータベースも参照することができます。

オートコンプリート機能も有効で、ちょっとしたSQLならすぐに試してみることができます。PostgreSQLの大文字小文字混在のカラムはダブルコーテーションで囲わないといけないので、逆に不便でした。

Linked Tables を定義してみる

mysqlpostgresql の準備ができたところで H2DB に接続して Linked Tables を作成してみたいと思います。

まずは mysqlworldデータベースの中の countryテーブルを my_country という名前で参照できるようにしてみます。

CREATE LINKED TABLE IF NOT EXISTS MY_COUNTRY(
'com.mysql.jdbc.Driver', 'jdbc:mysql://mysql-1:3306/world', 'mysql', 'mysql', 'country'
);

これだけで MY_COUNTRY というテーブルをローカルにあるテーブルのように参照できるようになります。

同様に、PG_CITYPG_COUNTRYLANGUAGE についてもテーブルを定義します。

CREATE LINKED TABLE IF NOT EXISTS PG_CITY(
'org.postgresql.Driver', 'jdbc:postgresql://postgres-1/world', 'postgres', 'postgres', 'city'
);

CREATE LINKED TABLE IF NOT EXISTS PG_COUNTRYLAUNGUAGE(
'org.postgresql.Driver', 'jdbc:postgresql://postgres-1/world', 'postgres', 'postgres', 'countrylanguage'
);

どんなSQLが発行されているか(MySQL

まずは条件なしで検索。

SELECT * FROM MY_COUNTRY 
SELECT * FROM country T

次は簡単な条件を付けてみます。

SELECT * FROM MY_COUNTRY where CODE ='JPN'
SELECT * FROM country T 
WHERE CODE>='JPN' AND CODE<='JPN'

単純な文字列の等号による一致条件のつもりだったのですが不等号の範囲検索に変換されてしまいました。なにか意図があるのでしょうがとりあえずヨシとします。

どんなSQLが発行されているか(PostgreSQL

SELECT * FROM PG_CITY 
SELECT * FROM public.city T
SELECT * FROM PG_CITY 
WHERE ID =10
SELECT * FROM public.city T 
WHERE ID>=$1 AND ID<=$2
ERROR:  column "id" does not exist at character 35

おっと。エラーが出てしまいました。どうやらDDLの段階でカラム名をダブルコーテーションで囲って大文字小文字を厳密に定義していたことが原因と思われる。。

DDLを修正してもう一度やり直し。PG_CITYPG_COUNTRYLANGUAGE についてもテーブル定義をやり直します。

SELECT * FROM PG_CITY 
WHERE ID =10
SELECT * FROM public.city T 
WHERE ID>=$1 AND ID<=$2
DETAIL:  parameters: $1 = '10', $2 = '10'

無事にクエリを発行することができました。

結合したらどうなるか(異DB同士

テーブル一つに対するクエリであれば、ほぼ等価の条件式が渡されるようなので、リンクされた側のDBで適切な実行計画が適用されることになりそうです。

では、2つのDBにまたがる結合をしたらどうなるのか。やってみたいと思います。

SELECT T1.NAME, T2.LANGUAGE  FROM MY_COUNTRY  T1
INNER JOIN PG_COUNTRYLAUNGUAGE  T2
ON T2.COUNTRYCODE = T1.CODE
AND  T2.ISOFFICIAL ='T'
WHERE T1.REGION  = 'North America'
;

北アメリカの国における公用語は?、という感じの意味合いになります。まず MY_COUNTRY を北アメリカで絞り込んだのち、国コードで PG_COUNTRYLANGUAGE から公用語を得る、という結合になることを想定してみました。

MySQL

SELECT * FROM country T WHERE CODE>='ABW' AND CODE<='ABW'
SELECT * FROM country T WHERE CODE>='AFG' AND CODE<='AFG'
SELECT * FROM country T WHERE CODE>='AFG' AND CODE<='AFG'
SELECT * FROM country T WHERE CODE>='AIA' AND CODE<='AIA'
SELECT * FROM country T WHERE CODE>='ALB' AND CODE<='ALB'
SELECT * FROM country T WHERE CODE>='AND' AND CODE<='AND'
SELECT * FROM country T WHERE CODE>='ANT' AND CODE<='ANT'
SELECT * FROM country T WHERE CODE>='ANT' AND CODE<='ANT'
SELECT * FROM country T WHERE CODE>='ARE' AND CODE<='ARE'
SELECT * FROM country T WHERE CODE>='ARG' AND CODE<='ARG'
SELECT * FROM country T WHERE CODE>='ARM' AND CODE<='ARM'
:
:

PostgreSQL

SELECT * FROM public.countrylanguage T WHERE ISOFFICIAL>=$1 AND ISOFFICIAL<=$2
-- parameters: $1 = 'T', $2 = 'T'

どうやら想定と逆に、PG_COUNTRYLANGUAGE から公用語の一覧を取得したのち、対応する国の一覧を取得。クエリには北アメリカでの絞り込みは入っていないので H2DB側で一番最後に行われたようです。

実行計画を見てみる

事後になりますが H2DBでの実行計画を見てみます。

EXPLAIN
SELECT T1.NAME, T2.LANGUAGE  FROM MY_COUNTRY  T1
INNER JOIN PG_COUNTRYLAUNGUAGE  T2
ON T2.COUNTRYCODE = T1.CODE
AND  T2.ISOFFICIAL ='T'
WHERE T1.REGION  = 'North America'
;
SELECT
    "T1"."NAME",
    "T2"."LANGUAGE"
FROM "PUBLIC"."PG_COUNTRYLAUNGUAGE" "T2"
    /* PUBLIC."": ISOFFICIAL = 'T' */
    /* WHERE T2.ISOFFICIAL = 'T'
    */
INNER JOIN "PUBLIC"."MY_COUNTRY" "T1"
    /* PUBLIC."": CODE = T2.COUNTRYCODE */
    ON 1=1
WHERE ("T1"."REGION" = 'North America')
    AND (("T2"."ISOFFICIAL" = 'T')
    AND ("T2"."COUNTRYCODE" = "T1"."CODE"))

FROM句で指定していたテーブルが MY_COUNTRY から PG_COUNTRYLANGUAGE に変わっていますね。H2DB では結合順序指定するヒント句はサポートされていません。性能を高めるには希望する結合順になるまで SQLをこねくり回すしかなさそうです。

結合したらどうなるか(同DB同士

同じDBにあるテーブル同士の結合も試してみます。

EXPLAIN
SELECT T1.COUNTRYCODE ,T1.DISTRICT , T1.NAME , T2.LANGUAGE
FROM PG_CITY T1
INNER JOIN PG_COUNTRYLAUNGUAGE T2
ON T2.COUNTRYCODE =T1.COUNTRYCODE 
WHERE T1.POPULATION >7000000
AND T2.ISOFFICIAL ='T'
;
SELECT
    "T1"."COUNTRYCODE",
    "T1"."DISTRICT",
    "T1"."NAME",
    "T2"."LANGUAGE"
FROM "PUBLIC"."PG_CITY" "T1"
    /* PUBLIC."": POPULATION > 7000000 */
    /* WHERE T1.POPULATION > 7000000
    */
INNER JOIN "PUBLIC"."PG_COUNTRYLAUNGUAGE" "T2"
    /* PUBLIC."": COUNTRYCODE = T1.COUNTRYCODE */
    ON 1=1
WHERE ("T2"."COUNTRYCODE" = "T1"."COUNTRYCODE")
    AND (("T1"."POPULATION" > 7000000)
    AND ("T2"."ISOFFICIAL" = 'T'))

人口が700万人超の都市のある国の公用語の一覧を得るクエリです。PostgreSQL へは以下のクエリが送信されました。

SELECT * FROM public.city T WHERE POPULATION>=$1
-- parameters: $1 = '7000000'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'BRA', $2 = 'BRA'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'GBR', $2 = 'GBR'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'IDN', $2 = 'IDN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'IND', $2 = 'IND'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'IND', $2 = 'IND'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'JPN', $2 = 'JPN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'CHN', $2 = 'CHN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'CHN', $2 = 'CHN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'KOR', $2 = 'KOR'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'MEX', $2 = 'MEX'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'PAK', $2 = 'PAK'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'TUR', $2 = 'TUR'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'RUS', $2 = 'RUS'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'USA', $2 = 'USA'

700万人超の都市の一覧を取得したのち、国コードを使って1国ずつ PG_COUNTRYLANGUAGE を取得していますね。ISOFFICIAL については記載がないので H2DB側で絞り込みを行っているのでしょう。

同じDBにあるテーブルであっても、結合をそのDBに任せず H2DB内で行っていることが分かりました。

まとめ

  • H2DB には他のDBのテーブルをH2DB内のテーブルのように見せかける機能がある。複数のシステムのDBを透過的に扱うのに便利。
  • 外部DBのテーブル定義に依存する。カラム名に大文字小文字混在を許すようなテーブルを参照するときは失敗することがあるので、事前に調査してビューなどを介すなど工夫が必要。
  • テーブル1つに対するクエリであればテーブルを持つDB上で抽出が行われるので、性能的には問題なさそう。
  • リンクテーブル同士での結合はサポートされている。しかし、H2DBの判断で実行計画が決まってしまうので性能が出ないことがある。
  • 結合するリンクテーブルが同じDBのテーブルであっても、結合がリンク先のDBに任されない。H2DBの判断によって行われる。

異なるシステムで使われているDBのテーブルを一時的に参照するような用途では便利かもしれない。しかし、複雑なクエリで問い合わせるときは性能を出すために苦労することになりそうだ。

]]>
/archives/1670/feed/ 0
[mysql] 変数を使用したクエリの実行 /archives/1058/ /archives/1058/#respond Wed, 20 Sep 2023 03:03:22 +0000 https://www.komina.info/?p=1058 hibernateなどのORMを使ったりするとSQLを自動生成して発行してくれるので、最近ではほとんどSQLを書かないでもDBを使ったプログラムが書けるようになりました。ちょっとした結合はJPQLで済ませてしまうことも多いです。

とはいえ性能に問題があるときには生成されたSQLに向き合わないといけません。hibernateであればシステム変数hibernate.use_sql_commentstrueを設定すると生成されたSQLがログに出力されるので、これを直接DBへ投げて原因を探ることができるわけです。

吐き出されるSQLは基本的に PreparedStaetment を用いたものなので引数はすべてクエスチョンマーク ? になっています。JPQLでバインド変数を :value1 とかにしていても一律 ? に置き換わります。例えばこんな感じ。

/* from models.UserMst where loginId = :user and deletedAt is null */
select usermst0_.id as id78_, usermst0_.loginId as loginId78_, usermst0_.password as password78_, … 
from user_mst usermst0_ where usermst0_.loginId=? and (usermst0_.deletedAt is null) limit ?

これをそのままmysqlに投げると ? のところでエラーになってしまいます。そこで下記のように記述します。(?の部分を実際に引数で置換してもよいですが、定数となると実行計画が変わってしまうことがあります。)

PREPARE my_stmt FROM '
select usermst0_.id as id78_, usermst0_.loginId as loginId78_, usermst0_.password as password78_, … 
from user_mst usermst0_ where usermst0_.loginId=? and (usermst0_.deletedAt is null) limit ?'
;
SET @LoginId = 'c12345';
SET @LimitCnt = 1;
EXECUTE my_stmt USING @LoginId, @LimitCnt;

このように引数を変数として定義し、クエリ実行時に渡すことで実際のプログラム実行時と同じ条件で実行することができます。

実行計画を見たいときは select句の前に explain と記述すればよいです。テーブルを参照するのにインデックスが利用されているか、どの順番に結合されているか、などが分かります。

実行計画の詳しい読み方に付いてはここでは割愛、詳しく解説されているサイトもあるようなので。

]]>
/archives/1058/feed/ 0
[mysql]端数処理(四捨五入、切り捨て、切り上げ) /archives/596/ /archives/596/#respond Wed, 25 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=596
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

四捨五入として round()関数があるが、挙動が好ましくないようなので truncate()関数を利用する。
truncate関数は端数を切り捨てる関数だが、切り捨て前に切り上げ分を加算することで四捨五入や切り上げを実現する。

四捨五入

3.45を小数第2位で四捨五入して、小数第1位までの値を得る。

select truncate(3.45 + 0.05, 1)

切り捨て

3.45を小数第1位までの値を得る。

select truncate(3.45, 1)

切り上げ

3.45を小数第1位位までの値を得る。

select truncate(3.45 + 0.09, 1)

0.09は3.401以上の値を切り捨て対象にすることになる。
3.4001以上の値も対象にしたいときは0.099を加算する。

]]>
/archives/596/feed/ 0
[mysql]文字列の結合 /archives/594/ /archives/594/#respond Tue, 24 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=594
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

文字列を結合するとき、直感的に「+」を使いたくなるところだが、concatという専用の関数があるのでこれを使用する。

mysql> select concat(123,456) as concat, 123+456 as plus;
+--------+------+
| concat | plus |
+--------+------+
| 123456 |  579 |
+--------+------+
1 row in set (0.00 sec)

なお引数の数は可変。

mysql> select concat(123,456,78,90);
+-----------------------+
| concat(123,456,78,90) |
+-----------------------+
| 1234567890            |
+-----------------------+
1 row in set (0.00 sec)
]]>
/archives/594/feed/ 0
[mysql]ユーザ操作 /archives/592/ /archives/592/#respond Mon, 23 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=592
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

ユーザ作成

GRANTコマンドで権限とパスワードを同時に設定する。

mysql> GRANT SELECT,INSERT,DELETE,UPDATE,CREATE,DROP,FILE,ALTER,INDEX ON *.* to

sample_user IDENTIFIED BY 'ABC123';
Query OK, 0 rows affected (0.00 sec)

自身のオプションを継承して、adminというユーザを作成し、パスワード'pass'を設定する。

mysql> GRANT ALL PRIVILEGES ON *.* TO admin@"192.168.0.%" IDENTIFIED BY 'pass' WITH GRANT OPTION;

"192.168.0.%"は、"192.168.0."からのログオンを許すという意味。同PC内であれば、"localhost"と書く。 ".*"はアクセスできるテーブルを指す。”データベース名.テーブル名” の形式。
"WITH GRANT OPTION"は、GRANT構文の実行権限を付与する意味。
"ALL PRIVILEGES"は全ての実行権限という意味、selectのみだったら"SELECT"と書く。

変更事項の即時反映

mysql> FLUSH PRIVILEGES;

ユーザ一覧

ユーザ情報もデータとして保存されているのでSELECT文を使って問い合わせる。

mysql> SELECT user, host, password FROM MYSQL.USER;
+-------+-----------+-------------------------------------------+
| user  | host      | password                                  |
+-------+-----------+-------------------------------------------+
| root  | localhost |                                           |
| root  | 127.0.0.1 |                                           |
| root  | ::1       |                                           |
| admin | localhost |                                           |
+-------+-----------+-------------------------------------------+
4 rows in set (0.00 sec)

パスワードはハッシュ値なので紛失パスワードを知ることは出来ない。
ハッシュ値なので同じワードを使えば同じハッシュ値になる。

]]>
/archives/592/feed/ 0
[mysql]パディング /archives/589/ /archives/589/#respond Sun, 22 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=589
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

前後に空白などを付け足して桁数をそろえたいとき。
左側に付け足したいときはlpad関数、右側はrpad関数を使う。

引数は、元となる値、望む桁数、埋める文字の3つ。

mysql> select lpad('abc', 5, '#') as hidari, rpad('abc', 5, '#') as migi;
+--------+-------+
| hidari | migi  |
+--------+-------+
| ##abc  | abc## |
+--------+-------+
1 row in set (0.00 sec)
]]>
/archives/589/feed/ 0
[mysql]トリガ作成例 /archives/577/ /archives/577/#respond Thu, 19 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=577
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

トリガの書式

テーブル作成のようにcreatedropコマンドを用いる。

CREATE
    [DEFINER = { user | CURRENT_USER }]
    TRIGGER trigger_name trigger_time trigger_event
    ON tbl_name FOR EACH ROW trigger_stmt
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
  • trigger_time には、AFTER(事後)/BEFORE(事前)を指定する。
  • trigger_event は、有効化するステートメントの種類を指定する。
    • INSERT指定:insertやreplaceなどで新しい行が挿入されたとき。
    • UPDATE指定:updateなどで行が修正されたとき。
    • DELETE指定:deleteやreplaceで行が削除されたとき。truncateやdrop tableは除く。
  • 同じtrigger_timetrigger_eventで複数の処理を登録することは出来ない。

自動的に変更ログを取る方法

あるテーブルへの変更をトリガ機能を使って逐一ログを取には。

準備

説明用テーブル構成、アドレス帳っぽいものを想定。

カラム名データ型備考
idintegerPK
namevarchar(30)
addressvarchar(255)
upd_usrvarchar(10)
table_x

ログ用テーブルはほとんど同じ構成で操作日時や操作者を記録できるようにしておく。また、PK指定は外しておく。

カラム名データ型備考
idintegerPK指定しない
namevarchar(30)
addressvarchar(255)
upd_usrvarchar(10)
ope_timetimestamp操作日時
ope_usrvarchar(10)操作者
table_log

テーブル作成クエリはこんな感じ。PKを指定し忘れたので後付してます。

mysql> CREATE TABLE table_x (
    ->  id integer,
    ->  name varchar(30),
    ->  address varchar(255),
    ->  upd_user varchar(10)
    -> );
Query OK, 0 rows affected (0.21 sec)
mysql> ALTER TABLE table_x ADD PRIMARY KEY (id);
Query OK, 0 rows affected (0.30 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> CREATE TABLE table_log (
    ->  id integer,
    ->  name varchar(30),
    ->  address varchar(255),
    ->  upd_user varchar(10),
    ->  ope_time timestamp,
    ->  ope_user varchar(10)
    -> );
Query OK, 0 rows affected (0.06 sec)

レコード追加時に動くトリガ

table_xへのレコード追加に連動して動く処理を書きます。NEWで更新後の情報を得られます。

mysql> delimiter $$
mysql> CREATE TRIGGER trg_x_insert BEFORE INSERT ON table_x
    ->  FOR EACH ROW
    ->  BEGIN
    ->   INSERT INTO table_log (id, name, address, upd_user, ope_user)
    ->     VALUES (NEW.id, NEW.name, NEW.address, NEW.upd_user, NEW.upd_user);
    ->  END;
    -> $$
Query OK, 0 rows affected (0.08 sec)

区切り記号の変更も一緒にしています。トリガとして登録する内容の区切り記号を誤認してしまわないための措置です。

動作テスト

mysql> insert into table_x (id, name, address, upd_user) values 1,'john','tokyo','user001');
Query OK, 1 row affected (0.05 sec)
mysql> select * from table_x;
+----+------+---------+----------+
| id | name | address | upd_user |
+----+------+---------+----------+
|  1 | john | tokyo   | user001  |
+----+------+---------+----------+
1 row in set (0.00 sec)
mysql> select * from table_log;
+------+------+---------+---------------------+----------+----------+
| id   | name | address | ope_time            | ope_user | upd_user |
+------+------+---------+---------------------+----------+----------+
|    1 | john | tokyo   | 2012-04-03 15:23:03 | user001  | user001  |
+------+------+---------+---------------------+----------+----------+
1 row in set (0.00 sec)

レコード更新時に働くトリガ

trigger_eventをUPDATEとして同様に登録します。今回は使用していませんが、OLDで更新前の情報が得られます。

mysql> CREATE TRIGGER trg_x_update BEFORE UPDATE ON table_x
    ->  FOR EACH ROW
    ->  BEGIN
    ->   INSERT INTO table_log (id, name, address, upd_user, ope_user)
    ->     VALUES (NEW.id, NEW.name, NEW.address, NEW.upd_user, NEW.upd_user);
    ->  END;
    -> $$
Query OK, 0 rows affected (0.06 sec)

レコード削除時に働くトリガ

trigger_eventをDELETEとして登録します。ただし操作ユーザは取得できないため、NULLのままとしています。また、deleteですとNEW情報は使えません。OLD情報のみとなります。

mysql> CREATE TRIGGER trg_x_delete BEFORE DELETE ON table_x
    ->  FOR EACH ROW
    ->  BEGIN
    ->   INSERT INTO table_log (id, name, address, upd_user, ope_user)
    ->     VALUES (OLD.id, NULL, NULL, NULL, NULL);
    ->  END;
    -> $$
Query OK, 0 rows affected (0.06 sec)

追加→変更→削除を行うと、table_logには下記のようなデータが残ります。

mysql> select * from table_log;
+------+-------+---------+---------------------+----------+----------+
| id   | name  | address | ope_time            | ope_user | upd_user |
+------+-------+---------+---------------------+----------+----------+
|    1 | john  | tokyo   | 2012-04-03 15:23:03 | user001  | user001  |
|    1 | jimmy | tokyo   | 2012-04-03 16:11:45 | user001  | user001  |
|    1 | NULL  | NULL    | 2012-04-03 16:12:13 | NULL     | NULL     |
+------+-------+---------+---------------------+----------+----------+
3 rows in set (0.00 sec)
]]>
/archives/577/feed/ 0
[mysql]データベース操作 /archives/573/ /archives/573/#respond Wed, 18 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=573
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

データベース一覧表示

mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)

データベース作成

CREATE DATABASEコマンドを用いる。

mysql> CREATE DATABASE sample_db;
Query OK, 1 row affected (0.00 sec)

データベース削除

DROP DATABASEコマンドを用いる。

mysql> DROP DATABASE sample_db;
Query OK, 0 rows affected (0.00 sec)

その他

  • 使用するデータベースを切り替えるには下記のようにデータベース名を指定してuseコマンドを実行する。
    mysql> use sample_db
    Databse changed

  • 使用中のデータベース内のテーブル一覧を参照したいとき。
    mysql> show tables;
  • テーブルのフィールドを確認したいとき。
    mysql> desc tablename;
  • 区切り記号を変更したいとき。(デフォルトはセミコロン)
    mysql> delimiter $$
]]>
/archives/573/feed/ 0
[mysql]テーブル名と大文字小文字 /archives/571/ /archives/571/#comments Tue, 17 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=571
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

OSによってファイル名の大文字小文字の扱いがと異なる。

たとえばLinuxは、大文字と小文字を明確に区別する。abcとAbcは別のファイルとして扱われる。

一方Windowsは、大文字と小文字を区別してファイル名を保持するが、abcとAbcは同じファイルとして扱われる。

MySQLのデータベース名やテーブル名の認識は、初期状態でOSのファイル名の扱いに準拠する設定となっている。
システム変数 lower_case_table_names に 0~2 の値を設定する。

  • 0 .. 大文字小文字を区別する
  • 1 .. 大文字小文字を区別しない(テーブル名をすべて小文字にして格納)
  • 2 .. 大文字小文字を区別しない(テーブル名をそのまま格納)

Linuxは標準で0、windowsは1、が設定されている。
そのためOSの異なるMySQL間で移行する場合は注意が必要である。

設定は、my.cnf (linux) / my.ini (windows) に下記のように記載する。

[mysqld]

lower_case_table_names = 1

サービスを再起動で設定内容が反映される。

]]>
/archives/571/feed/ 1
[mysql]SQLファイルの一括実行 /archives/567/ /archives/567/#respond Mon, 16 Nov 2020 21:00:00 +0000 https://www.komina.info/?p=567
【注意】
この記事は過去に別サイトで執筆したものを再掲載したものです。
内容が古くなっていて現在では適用できない場合や、もっと良い方法が出来ている場合があります。
 

SQLコマンドを羅列したファイルを一気に実行したいとき。

コマンドラインから実行したいデータベースを指定しつつ実行する場合。

shell> mysql database < textfile

データベースの指定がテキストファイル内に書かれている場合。

shell> mysql < textfile

mysqlを実行中の場合

mysql> source textfile;

Windows使用時はパスの区切りにスラッシュを使うこと。
例)

mysql> source C:/Users/komina/Documents/sample.sql;
]]>
/archives/567/feed/ 0