「食べ始まる」考
先日、こちらの新書を読んだんです。
- 作者: 荒川洋平
- 出版社/メーカー: 講談社
- 発売日: 2009/08/19
- メディア: 新書
- 購入: 3人 クリック: 11回
- この商品を含むブログ (18件) を見る
その中に、以下のような記述がありました。
不思議なことに終わりの局面では「終わる」「終える」と両方の補助の動詞が使えるのに、始まりの局面では「食べ始める」は言えても、「食べ始まる」とは言えません。
たしかに著者の仰る通りで、「食べ始まる」はふつう使わない。この記事はそれがなんでやねんという話です。明確な答えが書いてあるわけではないのでお気をつけください。
「終わる」「終える」、「始まる」「始める」の違い
「終わる」は、ラ行五段活用の自動詞で、「終える」はア行下一段活用の他動詞。 「始まる」は、ラ行五段活用の自動詞で、「始める」はマ行下一段活用の他動詞。 どちらのペアも意味はほとんど同じどうしで、それぞれ物事の終了と開始を意味する動詞ですが、他動詞のほうが、それのかかる主体にとって意識的に終了・開始を行っているニュアンスが含まれています。例えば「そろそろ試合が始まる」の場合は他の誰かによって開始の合図があるように思われますが、一方で「そろそろ試合を始める」の場合は話者自身によって試合が始められるように思われます。
これだけなら、「食べ終わる」のように「食べ始まる」を使っても何の問題もないように思えてきます。念のため、辞書の上では意味も確認してみましょう。太字のものは、自動詞・他動詞いずれにもある意味です。
終わる
- 1 続いていた物事が、そこでなくなる。しまいになる。済む。
- 2 (「終わった」「終わっている」の形で)廃れる。人気が衰える。
- 3 (「…におわる」「…でおわる」などの形で)期待された結果が得られないまま、それが最後の状態になる。
- 4 動詞の連用形に付いて、動作・作用が完結する意を表す。…しおわる。…てしまう。
- 5 しまいにする。終える。
- 6 生命が尽きる。死ぬ。
終える
- 1 続けてきたことを済ませる。終わらせる。
- 2 続いてきたことが終わる。
終わる・終えるは、終わるがより大きな意味を持ち、終えるを内包しているような関係(終わる⊂終える)になっています。
始まる
- 1 物事が行っていない状態から行う状態になる。行われだす。
- 2 新しく起こる。新たに発生する。
- 3 起因する。起源をもつ。
- 4 いつものくせが出る。
- 5 (「…ても始まらない」の形で)むだだ。手遅れだ。しようがない。
始める
- 1 物事を行っていない状態から行う状態にする。行いだす。
- 2 新しく起こす。新たにつくる。
- 3 いつものくせを出す。
- 4 (動詞の連用形などに付いて)その動作が行われだすことを表す。
始まる・始めるについてもほとんど同様で、始まるが始めるを内包する関係のようにも、部分共通のようにも思えます。これを見ても、「動詞+終わる」が言えて「動詞+始まる」が言えないのは、いささか不釣り合いな気がします。
言い換えて考えてみる
「食べ終える」は「食事を終える」に、「食べ終わる」は「食事が終わる」に言い換えることができます。同様に以下のように言い換えてみましょう。
- 「食事を終える」(食べ終える)
- 「食事が終わる」(食べ終わる)=「食事を終わる」
- 「食事を始める」(食べ始める)
- 「食事が始まる」(食べ始まる)=「食事を始まる」
こうして並べてみても、やはり「食べ始まる」はなんらおかしくないどころか、むしろ「始まる」を他動詞として「食事を始まる」と用い、その言い換えとして「食べ始まる」を使えないことのほうがおかしく感じられてきますよね。今こそ「食べ始まる」を使い始まるに相応しい時期なのかもしれません。
こういった変化には違和感があるかもしれませんが、かつて「大き(い)」の対義語として「小さな」しか無かった時代に、語尾の据わりを良くするために「大きな」「小さい」を発明し、これまで使ってきたように、こういった後からの発明はおかしなことではないはずです。
いざ使ってみる
ということで、今日から「動詞+始まる」の布教活動を始めようと思います。それを使うシチュエーションを考えてみましょう。
「食べ始まる」の場合
A「(電話がかかってくる)はい。Bさん?いつ帰ってくるの?」
B「もうすぐ帰るよ。みんなは晩ご飯もう食べた?」
A「ううん、ちょうど食べ始まるところだよ」
違和感があるかもしれませんが、最後の文を同じ自動詞の「うん、もう食べ終わるところだよ」にすれば違和感がありません。ということは、使い慣れてくれば「食べ始まる」も違和感が薄れてくるのではないでしょうか。とはいえ、これはもし「食べ始める」でもおかしくない、というのもその通りです。同様に「もう食べ終わるところ」が「もう食べ終えるところ」だったとしてもおかしくはないですが、何か独自の使い方を見つけたいところですね。
「歌い始まる」の場合
A「ライブ、まだ始まらないのかな?」
B「あ、見て。バンドの人が出てきたよ」
A「お、もうすぐ歌い始まるね」
この場合、「歌い始まる」ほどではありませんが、「もうすぐ歌い始めるね」にも少し違和感があります。「名詞+が+始まる」で「歌が始まるね」だとそこまで違和感はありませんが、「動詞+始まる」で同じ表現ができても不都合はなさそうです。
なぜ「動詞+始まる」を使わないのか
ここまで見てきた通り、「動詞+始まる」は文法的にもおかしなところはありませんし、使おうと思えば使うこともできそうな用法でした。しかし、使われていません。なぜでしょうか。答えが明確にあるわけではないですが、予想してみましょう。
他の表現で十分だから
上で見たように、「食べ始まる」は「食べ始める」(動詞+始まる)で十分ですし、「歌い始まる」は「歌が始まる」(名詞+が始まる)で十分伝わります。あえて区別する必要がなかったので、「動詞+始まる」が使われることもなかった可能性がありそうです。しかし、だとしたらどうして「動詞+終わる」と「動詞+終える」とが共存しているのか、という疑問が残ってしまいますね。
開始の感覚の問題
私たち日本人の無意識のなかには、『動作の開始はつねに意識的・自発的だから他動詞「始める」でしかありえないが、動作の終了は意識的・自発的である他動詞「終える」以外に、何らかの外的要因によって外発的に自動詞「終わる」こともありえる』という感覚があるのかもしれません。今でこそ「食べ終わる」「食べ終える」に大きな違いは無いものの、昔は内発的か外発的かによって使い分けており、一方で「始める」「始まる」にはその必要がなかったのではないでしょうか。
開始の責任の所在の問題
先程は動作の終了のほうに重きを置いていたのに対して、こちらは動作の開始に重きを置いた考え方です。動作を終了した人は誰であっても構わないから自動詞的な表現「動詞+終わる」が許されてきたが、動作の開始については誰が始めたのかを明確にするため、「動詞+始まる」が許されてこなかった、という可能性があるかもしれません。
結局答えは無いんですけど
ここまでに、いくつか可能性を挙げてきました。念のため以下におさらいします。
- 他の表現で十分だったから
- 動作の開始は主体的でしかありえないから
- 動作の開始は誰が行ったのか明確でなければならないから
結局のところ、このどれが正解なのか、またこれらのうちのどれでもなく、他に答えがあるのか、はたまたこれらのうちのいくつかが複合しているのか、わかりません(きちんと調べていないので)。でも、こういった日常的に見逃している不思議に、気付かせてくれる本と出会えたのは幸せだったなあと思っています。未読の方はぜひ一度読んでみてください。
それにしても、プロの言語学(日本語学)の方はこういった問題をどうやって追いかけているのでしょうかね。気になったので、このGWはそのへんの勉強をしてみたいと思います。
連続を失敗
ある夜、会社から帰ろうとして玄関で靴を探したとき、そこに自分の靴が無いことに気付いた。
決していじめられているわけではなくて
今働いている会社はいわゆるオフィスビルではなくかなり広めの一軒家なので、玄関では靴を脱ぎ、社内はスリッパで歩く必要がある。そのために帰宅の際には玄関で自分の靴を探して履くのだが、そこにあるはずの自分の靴がなかった。いや正確には、自分の靴だと思う靴はあるが、その確信が持てなかった。
手に取り、何度か見てみる。違和感は消えない。こんなタグは付いていたっけ。こんな色だったっけ。こんなにロゴは白かったっけ。ソールはこんな色だったっけ。
履いてみる。でもやっぱり変な感じがする。ニューバランスのゴアテックスが使われているものだから、十中八九これだと思うし、社内にほかに28センチの靴を履く人がいたとしても、まったく同じ靴を買って履いている可能性は非常に低いはずだ。そう考えても、やはり他人の靴を履いているような感覚が消えなかった*1。他に自分の靴だと思えるものがなかったので、「これは自分の靴だ」と言い聞かせて履いて帰った。
あの夜から1週間ぐらい経過したが、誰からも「自分の靴がなくなった」という話は聞かない。やっぱり自分の靴だと思われるが、違和感はうっすらとまだ自分の中にある。
信号を待っているときの違和感
まだ違和感の話は続く。信号を待っているとき、そしてそれが青に変わったとき、「本当の自分は痴呆老人で、自分自身をまだ思考がしっかりしている30代なんだと思い違えているだけなんじゃないか」と考えることがある。つまり目の前の青信号は実際には赤であり、現実の自分は今まさに死のうとしているのだ。
実際にはそうでないことはなんとなくわかっている。しかし、そうでないと証明することももちろんできない。自分の認識している現実を現実として受け止めて生きていくことしかできないのだとしたら、なんと我々は認識の前に無力だろうか。そんな頼りの認識が揺さぶられたとき、どうしようもなく振り回されてしまうのは、しかしながらさもありなんという思いがする。もはや虚構の青信号を信じ、現実の轢死を受け入れるしかない。
それからというもの、赤信号が青に変わると、同じように自分を確かめてしまうようになった。その確認に意味はないけれど。
知っているものしか見られない
世のメジャーが紙の辞書から電子辞書に移りつつある昨今*2、「電子辞書では自分が引きたいと思った項目しか見られない。いっぽう紙の辞書なら、同じページに並んでいる項目も一緒に目に入る。そのぶん知識を広げることができるのに、機会損失になってしまう!」というような話をよく耳にする。
自分は「電子辞書も紙の辞書も良し悪しだから、使い方にあわせて選べばよい。すべてが紙または電子になる必要はない」と考える、平凡で、面白みのNASA*3を持ちあわせた人間だが、ここではその是非について話したいわけではない*4。
かつて人類が Yahoo! 上で検索を行っていたころ、Webサイトはちょうど図書館の本のようにジャンルごとに分類され、並べられていた。利用者は見たいジャンルのページを開き、そこに並んだ Webサイトから見たいものを選んでアクセスしていた。ときには隣に(上や下に)並んでいるWebサイトが気になり、そこを見ることもした。目的のもの以外のWebサイトは、自分の知識の外にあるものだった。
現在はご存知 Google にWeb検索が取って代わられ、自分の知っている単語の組み合わせを用いて情報を検索するようになった。知識の外にあるものは、洪水のように誰かの興味が流れていく Twitter や Facebook などの SNS、または Wikipedia などの情報が羅列されているWebサイトで摂取するように、自分の場合はなっている。
かつて誰かが「これからの時代はなんでも検索できるから何も覚えなくていい」と言説しているのを聞いたが、実際にはそうはいかず、「少なくとも検索するための単語は覚えなくてはならない」という状態になっているように思うし、その検索語の種類や使い方を適切に身に着けていることが、検索したいものにたどり着くまでの速度に影響しているような気がする。また、言葉についての知識は、検索結果から情報を読み取るためにも重要だ。人間が言語を用いる限り、言語能力は重要であり続けるだろう。
いったい何の話だ
時間が連続しているものであり、左(または後方)からやってきて現在を追い越し、右(または前方)へ流れていくというイメージや感覚は、信じるに足るものなんだろうか*5。
ふいに目がさめて、状況を確認し、たとえばそこが祖父母の家で、いとこたちがまだ中学生で、自分は肉体的に7歳程度、階下から母親の呼び声がし、居間で「今日のお昼は外で食べよう」という会話がされていたなら、さっきまでの自分の現実はじつは夢であって、こっちが現実なんだと、少なくない違和感を押し込めてしまう可能性が無いと言いきれない。
靴を失くすまでの自分は、可能性が無いと言い切ったかもしれない。信号が青に変わるまでは。
「データベースが使えるようになりたい」と言われたので書いた
ある日うちの奥さん(エンジニアではない)から、「データベースが使えるようになりたいから教えてほしい」と相談を受けた。
一口にデータベースと言ってもいくつかあるので詳細を聞いてみると、彼女が意欲を示している「データベース」とは MySQL や PostgreSQL のこと*1で、今の職場に残されたレガシーなデータベースから古い情報を取り出すのに使うとのことだった。MySQL や PostgreSQL などのデータベース*2にはいくつかの機能があるが、情報の取り出しだけができればとりあえずは良いらしい。とはいえ「データベース使えますよ」と自信を持って言うために、情報の追加や更新、削除もできるようになっておきたい、ということだった。
そこで、そもそもデータベースはどんなもので、どういうことができるのか、どうすればできるのかを以下に簡単にまとめてみる。以下は奥さん向けに書いたものなので、普段エンジニア以外が耳慣れない言葉などはなるべく一度説明してから登場させるか、一度並べてから説明を後述することにする。ではいってみよう。
- 使う側にとっての「データベース」って何だろう
- 使うための用意
- 管理人と話そう
- 建物に入ろう
- 建物から帰ろう
- 建物の中でできること
- SQLコマンド
- MySQLコマンド
- コマンドを知る前に
- コマンドの説明をする前に本棚を作ろう
- コマンドを知ろう
- 定義済みのデータベースを一覧取得する(SHOW DATABASES)
- 操作したいデータベースを選ぶ(USE データベース名)
- 定義済みのテーブルを一覧取得する(SHOW TABLES)
- 定義済みのテーブルひとつを確認する(DESC テーブル名)
- テーブルの中から全カラムの情報を取得する(SELECT * FROM テーブル名)
- テーブルの中から特定のカラムの情報を取得する(SELECT カラム名 FROM テーブル名)
- テーブルの中から指定件数のデータを取得する(SELECT カラム名 FROM テーブル名 LIMIT 件数)
- テーブルの中から指定条件に完全一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE カラム名 = '合致させたい内容')
- テーブルの中から指定条件に部分一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE カラム名 LIKE '合致させたい内容')
- テーブルの中から複数条件のすべてに一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE 条件 AND 条件)
- テーブルの中から複数条件のいずれかまたは両方に一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE 条件 OR 条件)
- テーブルの取得結果をカラムの内容で並び替える(SELECT カラム名 FROM テーブル名 ORDER BY カラム名 昇順または降順)
- テーブルの取得条件に以上、以下を使う(SELECT カラム名 FROM テーブル名 WHERE カラム名 >= 数値 OR カラム名 <= 数値)
- テーブルの全件数を取得する(SELECT COUNT(*) FROM テーブル名)
- テーブルの内容を特定のカラムの内容でグループ分けする(SELECT * FROM テーブル名 GROUP BY カラム名)
- 指定されたカラムの最大値、最小値を取得する(SELECT MAX(カラム名), MIN(カラム名) FROM テーブル名 GROUP BY カラム名)
- 指定されたカラムに登録されている内容の合計値を取得する(SELECT SUM(カラム名) FROM テーブル名)
- 指定されたカラムに登録されている内容の文字数を取得する(SELECT LENGTH(カラム名) FROM テーブル名)
- 指定されたカラムに登録されている内容を重複を取り除いて表示する(SELECT DISTINCT カラム名 FROM テーブル名)
- 複数のカラムの内容や文字列を結合して結果に含める(SELECT CONCAT(文字列やカラム名, 文字列やカラム名, ...) FROM テーブル名)
- 取得結果に別名をつける(SELECT 取得結果 AS 別名)
- ふたつのテーブルを組み合わせて結果を取得する
- テーブルにデータを追加する(INSERT INTO テーブル名 ( カラム名 ) VALUES ( データ ))
- テーブルのデータを更新する(UPDATE テーブル名 SET カラム名 = 変更内容 WHERE 条件)
- データを削除する(DELETE FROM テーブル名 WHERE 条件)
- データベースの定義(CREATE DATABASE データベース名)
- データベース定義文の確認(SHOW CREATE DATABASE データベース名)
- データベースの削除(DROP DATABASE データベース名)
- テーブルの定義(CREATE TABLE テーブル名...)
- テーブルの定義文を確認する(SHOW CREATE TABLE テーブル名)
- テーブルの削除(DROP TABLE テーブル名)
- テーブルにカラムを追加する(ALTER TABLE テーブル名 ADD COLUMN カラム名 カラム設定)
- テーブルからカラムを削除する(ALTER TABLE テーブル名 DROP COLUMN カラム名)
- コマンドを入力していて起こりがちなトラブル
- 終わりに
使う側にとっての「データベース」って何だろう
データベースの用途を一言で表すなら、「情報を取り出しやすいように整理して置いておける場所」*3だと思う。言わば、たくさん本をしまっておいてすぐに取り出すことのできるとても便利な本棚と、その本棚から本を取ってきてくれる超素早い管理人がセットになったようなもの。
データベースを構成するもの
- 本棚
- 管理人(めちゃくちゃ素早い。本棚の目録を持っている)
※ 目録がなかったので代わりに金棒になりました。
「データベースってエクセルとかスプレッドシートと同じようなもんなんじゃないの」という話を聞くことがあるのは、その発言をする人がExcelやGoogle Spreadsheetsを「情報を取り出しやすいように整理して置いておける場所」として使っているからで、要するにその人にとっての用途が同じだから「同じようなもん」だと感じるのだろうと思う。ExcelやGoogle Spreadsheetsでできるように、「検索」機能を使って文字の部分一致検索をしたり、特定のセルの内容に一致する他のシートの行を引っ張ってきたりということは、データベースでもできる。
使うための用意
データベースを使うためには、以下のものが必要になる。すでにデータベースが用意されている環境なら、以下の中から不足しているものだけを用意しよう。説明していない言葉が出てくるが、ここでは列記するだけで後で説明する。
- データベースサーバ
- クライアント
データベースサーバとクライアントって何?
『データベースサーバ』は上でのたとえで言うところの、本棚と管理者と、それらがいる建物のことを指す。『クライアント』はあなたの召使いで、あなたが「あの本取ってきて」と頼むとデータベースサーバに出かけていき、管理者に「あの本取ってきて」と話しかけ、そこで本を見てその内容のコピーを取り、あなたのところまで持ち帰ってくる。他の人が見に来る可能性があるので、本そのものを持ち帰ることはできない。
この仕組みは、インターネットで見ているWebサイトと同じだと考えることもできる。あなたが今使っているブラウザ(ChromeやSafariやIEやEdgeなど)が『クライアント』で、彼に*4「 http://mizunokura.hatenablog.com/
という場所に書かれている内容を取ってきて」と頼むと、その場所にある建物まで出かけて行き、そこにいる管理者に見せてくれるよう話しかけ、見せてもらった内容のコピーを取り、あなたのところまで持ち帰ってくる。
データベースサーバの用意
すでにどこかにあることがわかっている場合
その場合、以下の情報を集める必要がある。ここでも先に列記してから後で説明する。
- データベースサーバの種別
- アドレス
- 認証情報
- ポート番号
データベースサーバの種別
データベースサーバにはいくつかの種類がある。
その他にもたくさんの種類があるが、市場シェア割合が高いのはこの4つ。それぞれに異なるクライアントを使用するので、種別を知っておく必要がある。こればっかりは聞くしかないので識者に質問しよう。種別が判明したら「MySQL クライアント インストール Mac」などで検索し、自分のパソコンにクライアントをインストールしよう。
アドレス
建物で例えるなら住所のこと。クライアントが出かけて行く先。IPアドレス(192.168.1.1 とか)だったり、ホストアドレス(db0001.local とか)だったりする。これも聞くしかないので聞こう。
認証情報
クライアントが建物に入っていくための名前(ユーザー名)とパスワード。これも聞くしかないので聞こう。
ポート番号
じつは、建物にはたくさん出入り口が用意されている。しかしながらセキュリティを確保するために、指定された出入り口以外を使うことはできないことになっている。MySQL の場合、初期設定では 3306 番の出入り口を使用する。これも聞くしかないので聞こう。聞いて「わからない」と言われたら、たいてい 3306 番だと思っておそらく問題ない。
とりあえず自分が使えればいい場合
その場合は、自分のパソコンの中に建物を建てて本棚を置いて管理人を連れてくることができる。データベースサーバの種別を決め、パソコンにインストールしよう(ググろう)。
みんなで使いたい場合
その場合も「自分が使えればいい場合」と考え方はほとんど同じだが、自分のパソコンの中ではなく、みんなが使うことのできる共通の場所に建物を建てる必要がある。その方法などなどを説明し始めると話が逸れるので割愛する。
クライアントの用意
上述の通り、データベースサーバの種別ごとに異なるので、種別を調べてから「MySQL クライアント インストール Mac」などで検索し、自分のパソコンにクライアントをインストールしよう。
管理人と話そう
データベースサーバとクライアントの準備ができたら、さっそく建物の中にいる管理人に挨拶してみよう。都合上ここからは MySQL に絞って説明していく。
建物に入ろう
データベースサーバという建物の中に入っていくためには、上述の「アドレス」と「認証情報」と「ポート番号」とを使う必要がある。コマンドラインクライアント(黒背景に白文字の画面で使用するクライアント)の場合、ターミナルに以下を入力($
は入力しない)して、エンターキーを押して実行する。
$ mysql -u ユーザー名 -h アドレス --port ポート番号 -p
このような、パソコンに対する命令文を「コマンド」と呼ぶ。
また、上記のコマンドのポート番号については初期設定で3306になっているので省略できる。さらに、パスワードが設定されていない場合にも省略でき、自分のパソコンの中に建物を建てた場合アドレスも省略できるので、以下の内容で実行することができる。
$ mysql -u ユーザー名
自分でデータベースサーバをインストールした場合、ユーザー名は、とくに変更していないのであれば root
になっている。
例えば以下のような表示が出てくれば、建物に入ること(ログイン)に成功している。
$ mysql -uroot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.21 Homebrew Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
上の mysql>
の部分がクライアントの待機状態を示す文字列で、「管理人になんて言ってきましょうか」と自分に聞いてきてると考えると良いかもしれない。
パスワードの入力を促される場合
実行時に -p
を付けている場合、以下のようにパスワードの入力を促される場合がある。パスワードを入力しよう。画面に入力している文字が何も表示されないが、そのまま入力してエンターキーを押せば問題ない。
$ mysql -u ユーザー名 -p Enter password:
パスワードを間違えていると以下のようなエラーメッセージが表示される。
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
また、以下のようにパスワードをコマンドに含めてしまうこともできる。
$ mysql -u ユーザー名 -pパスワード
MySQL サーバが起動していない場合
以下のようなエラーメッセージが出る場合、MySQL データベースサーバが起動してない。例えるなら、建物も本棚も管理人もいない状態である。
$ mysql -uroot ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
Mac で homebrew を使ってインストールした場合、以下のコマンドを使って起動することができる。
$ brew services start mysql
建物から帰ろう
いつでもクライアントを終了できるように、その方法を確認しておこう。mysql>
の表示に続けて quit
と入力し、エンターキーを押せば良い。
mysql> quit
また、 Ctrl+D キー
でもクライアントを即座に終了することができる。
建物の中でできること
MySQL データベースサーバでは、大きく分けてふたつのことができる。どちらもクライアントが管理人に対して話しかけることで効果を発揮する。
SQLコマンド
SQLコマンドとは、データベースを操作する際に使用するために作られた命令文の集合*5で、最初のバージョンが発表されてから各データベースサーバがそれぞれに取り入れ、さらに独自の拡張を行ってきたもの。あまりにも各データベースサーバごとに異なってしまうのを防ぐために作られた標準統一規格が存在するので、基本的にはある程度共通しているが、異なっている部分もある。
大きく分けて、以下の操作ができる。カッコ内は本棚の例えをした場合のイメージ。
- データ定義(本棚や、本棚に置く内容を決めたりする)
- データ操作(本棚に本を置いたり、削除したり、上書きしたりする)
- データ制御(建物にはいれる人を決めたり、本棚の内容を変えるのを制限したりする)
MySQLコマンド
SQLコマンドに定義されていないものの、各データベースサーバが必要に応じて追加した独自の命令文の集合。それぞれ独自のコマンドなので、データベースサーバごとに大きく異なっている。「MySQLコマンド」という言葉は筆者が名付けただけなので、一般には通じないことに注意。
コマンドを知る前に
ここから各コマンドについて説明するが、その前に知っておくべきこと、用意しておくべきことを説明する。
コマンドの説明の前に知っておくべきこと
データベースサーバ内では、以下の概念を取り扱う。
- データベース
- テーブル
- カラム
- ユーザー
データベース
「情報を取り扱うための入れ物の入れ物」。本棚の例えで言うところの、管理人が管理しているたくさんの本棚の群れのこと。Excelなら1つのxlsxファイル。Google Spreadsheetsなら1つのスプレッドシート。
テーブル
「情報を取り扱うための入れ物」。本棚の例えで言うところの、たくさんの本棚のうちのひとつ。Excelなら1つのxlsxファイルの中の1枚のシート。Google Spreadsheetsなら1つのスプレッドシートの中の1枚のシート。
カラム
「入れ物の中の間仕切りと、仕切られた空間につけられた名前」。本棚の例えで言うところの、「書名」や「著者名」といった分類するための情報区分。ExcelやGoogle Spreadsheetsなら、たいてい1行目に記載するその列の名前。
ユーザー
「操作をする人」。本棚の例えで言うところの、建物にはいる人の名前とパスワード。Excelなら操作している自分自身。Google Spreadsheetsなら、Google にログインするアカウント。
コマンドの説明をする前に本棚を作ろう
コマンドの説明をするにあたって、手元に動作を確認する環境があると理解しやすくなる。MySQL の場合は公式にデータベースとテーブルのセットを用意してくれているので、ダウンロードして使うと良い。
参照: https://dev.mysql.com/doc/index-other.html
ダウンロードしたZIPファイルを解凍して作成された world.sql
を mysql クライアントに渡してやると、世界の国々の人口や首都、都市の人口などのデータ、言語などが入ったデータベースを作成してくれる。
$ mysql -u ユーザー名 < ./world.sql
※ ./world.sql
の部分は各自ダウンロードしたファイルがある場所までのディレクトリパスを入力する。もしそれが Mac のダウンロードフォルダなら、
$ mysql -u ユーザー名 < ~/Downloads/world.sql
とすることで作成できる。
コマンドを知ろう
ここからコマンドについて説明していく。基本的にエンターキーが押されるまでクライアントは管理人に話しかけに行かない。また、基本的に末尾に ;
(セミコロン)や ¥G
が付いていなければ、管理人はコマンド入力がまだ続いていると判断して、何もしない((USE
など一部コマンドは除く))。以下ではコマンドを大文字表記しているが、小文字でも問題ない。
定義済みのデータベースを一覧取得する(SHOW DATABASES)
データベースサーバ内のデータベース(建物内にある本棚群)の一覧を取ってきてもらい、見るMySQLコマンド。
mysql> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | world | +--------------------+ 5 rows in set (0.00 sec)
ここで表示されたのは、データベースの名前だ。 world
以外の4つは、MySQL データベースサーバインストール時から用意されているデータベース管理用のもの(管理人が使うもの)なので、直接触る必要はない。
操作したいデータベースを選ぶ(USE データベース名)
操作したい本棚の名前を指定するMySQLコマンド。
mysql> use world; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed
本棚を指定しないまま、先に本棚を指定しているべきコマンドを入力した場合、以下のエラーになる。
mysql> show tables; ERROR 1046 (3D000): No database selected
ログイン時(建物に入る時)に以下のようにすることで、USE データベース名
を入力することなくデータベースを指定することもできる。
$ mysql -u ユーザー名 -h アドレス --port ポート番号 -p データベース名 # または $ mysql -u ユーザー名 データベース名 # など
定義済みのテーブルを一覧取得する(SHOW TABLES)
データベース内のテーブル(本棚群の中の本棚)の一覧を取ってきてもらい、見るMySQLコマンド。
mysql> SHOW TABLES; +-----------------+ | Tables_in_world | +-----------------+ | city | | country | | countrylanguage | +-----------------+ 3 rows in set (0.00 sec)
定義済みのテーブルひとつを確認する(DESC テーブル名)
データベース内のテーブルひとつの情報を取ってきてもらい、見るMySQLコマンド。ここでは、上で確認した中にある country
テーブルの情報を確認しよう。
mysql> DESC country; +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ | Code | char(3) | NO | PRI | | | | Name | char(52) | NO | | | | | Continent | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO | | Asia | | | Region | char(26) | NO | | | | | SurfaceArea | float(10,2) | NO | | 0.00 | | | IndepYear | smallint(6) | YES | | NULL | | | Population | int(11) | NO | | 0 | | | LifeExpectancy | float(3,1) | YES | | NULL | | | GNP | float(10,2) | YES | | NULL | | | GNPOld | float(10,2) | YES | | NULL | | | LocalName | char(45) | NO | | | | | GovernmentForm | char(45) | NO | | | | | HeadOfState | char(60) | YES | | NULL | | | Capital | int(11) | YES | | NULL | | | Code2 | char(2) | NO | | | | +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ 15 rows in set (0.01 sec)
Field
はカラムに付けられた名前。 Type
はカラムに入れられるデータの種類。Null
はそのカラムにnull(空のデータ)が入ることを許容するかどうか。Key
はそのカラムの一意制約(後述)の情報。Default
はそのカラムに値を指定しなかった場合に自動的で入る値。Extra
は付随情報。
また Field
には、日本語を使うこともできる。
テーブルの中から全カラムの情報を取得する(SELECT * FROM テーブル名)
テーブルの中に定義されている全カラムの情報を取得するコマンド。FROM
のあとに続けて、データを取ってきてほしいテーブル名を指定する。ここでは、上で情報を確認した country
テーブルの内容を取得してみよう。
mysql> SELECT * FROM country; +------+----------------------------------------------+---------------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------------+--------------------------------------+---------+-------+ | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+----------------------------------------------+---------------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------------+--------------------------------------+---------+-------+ | ABW | Aruba | North America | Caribbean | 193.00 | NULL | 103000 | 78.4 | 828.00 | 793.00 | Aruba | Nonmetropolitan Territory of The Netherlands | Beatrix | 129 | AW | | AFG | Afghanistan | Asia | Southern and Central Asia | 652090.00 | 1919 | 22720000 | 45.9 | 5976.00 | NULL | Afganistan/Afqanestan | Islamic Emirate | Mohammad Omar | 1 | AF | | AGO | Angola | Africa | Central Africa | 1246700.00 | 1975 | 12878000 | 38.3 | 6648.00 | 7984.00 | Angola | Republic | José Eduardo dos Santos | 56 | AO | (中略) | ZAF | South Africa | Africa | Southern Africa | 1221037.00 | 1910 | 40377000 | 51.1 | 116729.00 | 129092.00 | South Africa | Republic | Thabo Mbeki | 716 | ZA | | ZMB | Zambia | Africa | Eastern Africa | 752618.00 | 1964 | 9169000 | 37.2 | 3377.00 | 3922.00 | Zambia | Republic | Frederick Chiluba | 3162 | ZM | | ZWE | Zimbabwe | Africa | Eastern Africa | 390757.00 | 1980 | 11669000 | 37.8 | 5951.00 | 8670.00 | Zimbabwe | Republic | Robert G. Mugabe | 4068 | ZW | +------+----------------------------------------------+---------------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------------+--------------------------------------+---------+-------+ 239 rows in set (0.01 sec)
239行もあるので、画面が文字で埋まってしまい大変なことになる。そこで、ひとまず名前だけを取ってきてみたい。
テーブルの中から特定のカラムの情報を取得する(SELECT カラム名 FROM テーブル名)
DESC テーブル名
で確認したカラム名(Field
の部分)を指定することで、そのカラムの情報だけを取ってくることができる。
mysql> SELECT Name FROM country; +----------------------------------------------+ | Name | +----------------------------------------------+ | Aruba | | Afghanistan | | Angola | (中略) | South Africa | | Zambia | | Zimbabwe | +----------------------------------------------+ 239 rows in set (0.00 sec)
また、カラム名はカンマ(,
)で区切ることで複数指定することもできる。また、全カラム取得時に指定したアスタリスク(*
)は、じつは「全カラム」という意味を持っている。
mysql> SELECT Code, Name FROM country; +------+----------------------------------------------+ | Code | Name | +------+----------------------------------------------+ | ABW | Aruba | | AFG | Afghanistan | | AGO | Angola | (中略) | ZAF | South Africa | | ZMB | Zambia | | ZWE | Zimbabwe | +------+----------------------------------------------+ 239 rows in set (0.00 sec)
これで多少見やすくはなったが、行数が多いのでまだすこしわかりにくいと思う。そこで、今度は指定した件数だけを取ってきてみたい。
テーブルの中から指定件数のデータを取得する(SELECT カラム名 FROM テーブル名 LIMIT 件数)
LIMIT 件数
を指定することで、指定件数のデータだけを取ってくることができる。
mysql> SELECT Code,Name FROM country LIMIT 10; +------+----------------------+ | Code | Name | +------+----------------------+ | ABW | Aruba | | AFG | Afghanistan | | AGO | Angola | | AIA | Anguilla | | ALB | Albania | | AND | Andorra | | ANT | Netherlands Antilles | | ARE | United Arab Emirates | | ARG | Argentina | | ARM | Armenia | +------+----------------------+ 10 rows in set (0.00 sec)
これで画面が平和になった。しかし、今度は11行目以降が見えなくなってしまった。次の10件を取ってきてもらうには、 OFFSET 件数
を末尾でさらに指定する。
mysql> SELECT Code,Name FROM country LIMIT 10 OFFSET 10; +------+-----------------------------+ | Code | Name | +------+-----------------------------+ | ASM | American Samoa | | ATA | Antarctica | | ATF | French Southern territories | | ATG | Antigua and Barbuda | | AUS | Australia | | AUT | Austria | | AZE | Azerbaijan | | BDI | Burundi | | BEL | Belgium | | BEN | Benin | +------+-----------------------------+ 10 rows in set (0.00 sec)
同様に、次の21行目以降を見るためには OFFSET 20
を指定すれば良い。これで少しずつ見ることができるようなった。では、OFFSET の件数を変えて、日本(Japan)の情報だけを見てみよう。
mysql> SELECT Code,Name FROM country LIMIT 10 OFFSET 100; +------+--------------------------------+ | Code | Name | +------+--------------------------------+ | IOT | British Indian Ocean Territory | | IRL | Ireland | | IRN | Iran | | IRQ | Iraq | | ISL | Iceland | | ISR | Israel | | ITA | Italy | | JAM | Jamaica | | JOR | Jordan | | JPN | Japan | +------+--------------------------------+ 10 rows in set (0.00 sec)
…あった。Japan は110行目にようやく見つかった。しかし、今回のように239件しかないテーブルならともかく、たとえば10万件あるテーブルの中から特定のデータ1件を見つけるために、OFFSET 10、20、40…と繰り返すのは手間がかかりすぎる。そこで、日本のように名前がわかっている国のデータを、名前で探せるようにしたい。
テーブルの中から指定条件に完全一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE カラム名 = '合致させたい内容')
WHERE
に続けて、カラム名と合致させたい内容を指定することで、条件に合うデータ行だけを取得することができる。ここでは国名(Name)が日本(Japan)になっているデータを取ってきてほしいので、WHERE Name = 'Japan'
と指定する。
mysql> SELECT * FROM country WHERE Name = 'Japan'; +------+-------+-----------+--------------+-------------+-----------+------------+----------------+------------+------------+--------------+-------------------------+-------------+---------+-------+ | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+-------+-----------+--------------+-------------+-----------+------------+----------------+------------+------------+--------------+-------------------------+-------------+---------+-------+ | JPN | Japan | Asia | Eastern Asia | 377829.00 | -660 | 126714000 | 80.7 | 3787042.00 | 4192638.00 | Nihon/Nippon | Constitutional Monarchy | Akihito | 1532 | JP | +------+-------+-----------+--------------+-------------+-----------+------------+----------------+------------+------------+--------------+-------------------------+-------------+---------+-------+ 1 row in set (0.00 sec)
無事取ってこれた。しかし横長になってしまってすこし見づらい。その場合は、末尾の ;
を ¥G
に変えることで、横並びに表示されているデータを縦並びに表示することができる。
mysql> SELECT * FROM country WHERE Name = 'Japan'\G *************************** 1. row *************************** Code: JPN Name: Japan Continent: Asia Region: Eastern Asia SurfaceArea: 377829.00 IndepYear: -660 Population: 126714000 LifeExpectancy: 80.7 GNP: 3787042.00 GNPOld: 4192638.00 LocalName: Nihon/Nippon GovernmentForm: Constitutional Monarchy HeadOfState: Akihito Capital: 1532 Code2: JP 1 row in set (0.00 sec)
では、同じように大陸(Continent)がアジア(Asia)になっている国の一覧を取ってきてみよう。
mysql> SELECT * FROM country WHERE Continent = 'Asia'\G (中略) *************************** 51. row *************************** Code: YEM Name: Yemen Continent: Asia Region: Middle East SurfaceArea: 527968.00 IndepYear: 1918 Population: 18112000 LifeExpectancy: 59.8 GNP: 6041.00 GNPOld: 5729.00 LocalName: Al-Yaman GovernmentForm: Republic HeadOfState: Ali Abdallah Salih Capital: 1780 Code2: YE 51 rows in set (0.00 sec)
今度は逆に見辛くなってしまったので、横長にしてみる。
mysql> SELECT * FROM country WHERE Continent = 'Asia'; +------+----------------------+-----------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------+----------------------------------+---------+-------+ | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+----------------------+-----------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------+----------------------------------+---------+-------+ | AFG | Afghanistan | Asia | Southern and Central Asia | 652090.00 | 1919 | 22720000 | 45.9 | 5976.00 | NULL | Afganistan/Afqanestan | Islamic Emirate | Mohammad Omar | 1 | AF | | ARE | United Arab Emirates | Asia | Middle East | 83600.00 | 1971 | 2441000 | 74.1 | 37966.00 | 36846.00 | Al-Imarat al-´Arabiya al-Muttahida | Emirate Federation | Zayid bin Sultan al-Nahayan | 65 | AE | | ARM | Armenia | Asia | Middle East | 29800.00 | 1991 | 3520000 | 66.4 | 1813.00 | 1627.00 | Hajastan | Republic | Robert Kotšarjan | 126 | AM | | AZE | Azerbaijan | Asia | Middle East | 86600.00 | 1991 | 7734000 | 62.9 | 4127.00 | 4100.00 | Azärbaycan | Federal Republic | Heydär Äliyev | 144 | AZ | | BGD | Bangladesh | Asia | Southern and Central Asia | 143998.00 | 1971 | 129155000 | 60.2 | 32852.00 | 31966.00 | Bangladesh | Republic | Shahabuddin Ahmad | 150 | BD | | BHR | Bahrain | Asia | Middle East | 694.00 | 1971 | 617000 | 73.0 | 6366.00 | 6097.00 | Al-Bahrayn | Monarchy (Emirate) | Hamad ibn Isa al-Khalifa | 149 | BH | | BRN | Brunei | Asia | Southeast Asia | 5765.00 | 1984 | 328000 | 73.6 | 11705.00 | 12460.00 | Brunei Darussalam | Monarchy (Sultanate) | Haji Hassan al-Bolkiah | 538 | BN | | BTN | Bhutan | Asia | Southern and Central Asia | 47000.00 | 1910 | 2124000 | 52.4 | 372.00 | 383.00 | Druk-Yul | Monarchy | Jigme Singye Wangchuk | 192 | BT | | CHN | China | Asia | Eastern Asia | 9572900.00 | -1523 | 1277558000 | 71.4 | 982268.00 | 917719.00 | Zhongquo | People'sRepublic | Jiang Zemin | 1891 | CN | | CYP | Cyprus | Asia | Middle East | 9251.00 | 1960 | 754700 | 76.7 | 9333.00 | 8246.00 | Kýpros/Kibris | Republic | Glafkos Klerides | 2430 | CY | | GEO | Georgia | Asia | Middle East | 69700.00 | 1991 | 4968000 | 64.5 | 6064.00 | 5924.00 | Sakartvelo | Republic | Eduard Ševardnadze | 905 | GE | | HKG | Hong Kong | Asia | Eastern Asia | 1075.00 | NULL | 6782000 | 79.5 | 166448.00 | 173610.00 | Xianggang/Hong Kong | Special Administrative Region of China | Jiang Zemin | 937 | HK | | IDN | Indonesia | Asia | Southeast Asia | 1904569.00 | 1945 | 212107000 | 68.0 | 84982.00 | 215002.00 | Indonesia | Republic | Abdurrahman Wahid | 939 | ID | | IND | India | Asia | Southern and Central Asia | 3287263.00 | 1947 | 1013662000 | 62.5 | 447114.00 | 430572.00 | Bharat/India | Federal Republic | Kocheril Raman Narayanan | 1109 | IN | | IRN | Iran | Asia | Southern and Central Asia | 1648195.00 | 1906 | 67702000 | 69.7 | 195746.00 | 160151.00 | Iran | Islamic Republic | Ali Mohammad Khatami-Ardakani | 1380 | IR | | IRQ | Iraq | Asia | Middle East | 438317.00 | 1932 | 23115000 | 66.5 | 11500.00 | NULL | Al-´Iraq | Republic | Saddam Hussein al-Takriti | 1365 | IQ | | ISR | Israel | Asia | Middle East | 21056.00 | 1948 | 6217000 | 78.6 | 97477.00 | 98577.00 | Yisra’el/Isra’il | Republic | Moshe Katzav | 1450 | IL | | JOR | Jordan | Asia | Middle East | 88946.00 | 1946 | 5083000 | 77.4 | 7526.00 | 7051.00 | Al-Urdunn | Constitutional Monarchy | Abdullah II | 1786 | JO | | JPN | Japan | Asia | Eastern Asia | 377829.00 | -660 | 126714000 | 80.7 | 3787042.00 | 4192638.00 | Nihon/Nippon | Constitutional Monarchy | Akihito | 1532 | JP | | KAZ | Kazakstan | Asia | Southern and Central Asia | 2724900.00 | 1991 | 16223000 | 63.2 | 24375.00 | 23383.00 | Qazaqstan | Republic | Nursultan Nazarbajev | 1864 | KZ | | KGZ | Kyrgyzstan | Asia | Southern and Central Asia | 199900.00 | 1991 | 4699000 | 63.4 | 1626.00 | 1767.00 | Kyrgyzstan | Republic | Askar Akajev | 2253 | KG | | KHM | Cambodia | Asia | Southeast Asia | 181035.00 | 1953 | 11168000 | 56.5 | 5121.00 | 5670.00 | Kâmpuchéa | Constitutional Monarchy | Norodom Sihanouk | 1800 | KH | | KOR | South Korea | Asia | Eastern Asia | 99434.00 | 1948 | 46844000 | 74.4 | 320749.00 | 442544.00 | Taehan Min’guk (Namhan) | Republic | Kim Dae-jung | 2331 | KR | | KWT | Kuwait | Asia | Middle East | 17818.00 | 1961 | 1972000 | 76.1 | 27037.00 | 30373.00 | Al-Kuwayt | Constitutional Monarchy (Emirate) | Jabir al-Ahmad al-Jabir al-Sabah | 2429 | KW | | LAO | Laos | Asia | Southeast Asia | 236800.00 | 1953 | 5433000 | 53.1 | 1292.00 | 1746.00 | Lao | Republic | Khamtay Siphandone | 2432 | LA | | LBN | Lebanon | Asia | Middle East | 10400.00 | 1941 | 3282000 | 71.3 | 17121.00 | 15129.00 | Lubnan | Republic | Émile Lahoud | 2438 | LB | | LKA | Sri Lanka | Asia | Southern and Central Asia | 65610.00 | 1948 | 18827000 | 71.8 | 15706.00 | 15091.00 | Sri Lanka/Ilankai | Republic | Chandrika Kumaratunga | 3217 | LK | | MAC | Macao | Asia | Eastern Asia | 18.00 | NULL | 473000 | 81.6 | 5749.00 | 5940.00 | Macau/Aomen | Special Administrative Region of China | Jiang Zemin | 2454 | MO | | MDV | Maldives | Asia | Southern and Central Asia | 298.00 | 1965 | 286000 | 62.2 | 199.00 | NULL | Dhivehi Raajje/Maldives | Republic | Maumoon Abdul Gayoom | 2463 | MV | | MMR | Myanmar | Asia | Southeast Asia | 676578.00 | 1948 | 45611000 | 54.9 | 180375.00 | 171028.00 | Myanma Pye | Republic | kenraali Than Shwe | 2710 | MM | | MNG | Mongolia | Asia | Eastern Asia | 1566500.00 | 1921 | 2662000 | 67.3 | 1043.00 | 933.00 | Mongol Uls | Republic | Natsagiin Bagabandi | 2696 | MN | | MYS | Malaysia | Asia | Southeast Asia | 329758.00 | 1957 | 22244000 | 70.8 | 69213.00 | 97884.00 | Malaysia | Constitutional Monarchy, Federation | Salahuddin Abdul Aziz Shah Alhaj | 2464 | MY | | NPL | Nepal | Asia | Southern and Central Asia | 147181.00 | 1769 | 23930000 | 57.8 | 4768.00 | 4837.00 | Nepal | Constitutional Monarchy | Gyanendra Bir Bikram | 2729 | NP | | OMN | Oman | Asia | Middle East | 309500.00 | 1951 | 2542000 | 71.8 | 16904.00 | 16153.00 | ´Uman | Monarchy (Sultanate) | Qabus ibn Sa´id | 2821 | OM | | PAK | Pakistan | Asia | Southern and Central Asia | 796095.00 | 1947 | 156483000 | 61.1 | 61289.00 | 58549.00 | Pakistan | Republic | Mohammad Rafiq Tarar | 2831 | PK | | PHL | Philippines | Asia | Southeast Asia | 300000.00 | 1946 | 75967000 | 67.5 | 65107.00 | 82239.00 | Pilipinas | Republic | Gloria Macapagal-Arroyo | 766 | PH | | PRK | North Korea | Asia | Eastern Asia | 120538.00 | 1948 | 24039000 | 70.7 | 5332.00 | NULL | Choson Minjujuui In´min Konghwaguk (Bukhan) | Socialistic Republic | Kim Jong-il | 2318 | KP | | PSE | Palestine | Asia | Middle East | 6257.00 | NULL | 3101000 | 71.4 | 4173.00 | NULL | Filastin | Autonomous Area | Yasser (Yasir) Arafat | 4074 | PS | | QAT | Qatar | Asia | Middle East | 11000.00 | 1971 | 599000 | 72.4 | 9472.00 | 8920.00 | Qatar | Monarchy | Hamad ibn Khalifa al-Thani | 2973 | QA | | SAU | Saudi Arabia | Asia | Middle East | 2149690.00 | 1932 | 21607000 | 67.8 | 137635.00 | 146171.00 | Al-´Arabiya as-Sa´udiya | Monarchy | Fahd ibn Abdul-Aziz al-Sa´ud | 3173 | SA | | SGP | Singapore | Asia | Southeast Asia | 618.00 | 1965 | 3567000 | 80.1 | 86503.00 | 96318.00 | Singapore/Singapura/Xinjiapo/Singapur | Republic | Sellapan Rama Nathan | 3208 | SG | | SYR | Syria | Asia | Middle East | 185180.00 | 1941 | 16125000 | 68.5 | 65984.00 | 64926.00 | Suriya | Republic | Bashar al-Assad | 3250 | SY | | THA | Thailand | Asia | Southeast Asia | 513115.00 | 1350 | 61399000 | 68.6 | 116416.00 | 153907.00 | Prathet Thai | Constitutional Monarchy | Bhumibol Adulyadej | 3320 | TH | | TJK | Tajikistan | Asia | Southern and Central Asia | 143100.00 | 1991 | 6188000 | 64.1 | 1990.00 | 1056.00 | Toçikiston | Republic | Emomali Rahmonov | 3261 | TJ | | TKM | Turkmenistan | Asia | Southern and Central Asia | 488100.00 | 1991 | 4459000 | 60.9 | 4397.00 | 2000.00 | Türkmenostan | Republic | Saparmurad Nijazov | 3419 | TM | | TMP | East Timor | Asia | Southeast Asia | 14874.00 | NULL | 885000 | 46.0 | 0.00 | NULL | Timor Timur | Administrated by the UN | José Alexandre Gusmão | 1522 | TP | | TUR | Turkey | Asia | Middle East | 774815.00 | 1923 | 66591000 | 71.0 | 210721.00 | 189122.00 | Türkiye | Republic | Ahmet Necdet Sezer | 3358 | TR | | TWN | Taiwan | Asia | Eastern Asia | 36188.00 | 1945 | 22256000 | 76.4 | 256254.00 | 263451.00 | T’ai-wan | Republic | Chen Shui-bian | 3263 | TW | | UZB | Uzbekistan | Asia | Southern and Central Asia | 447400.00 | 1991 | 24318000 | 63.7 | 14194.00 | 21300.00 | Uzbekiston | Republic | Islam Karimov | 3503 | UZ | | VNM | Vietnam | Asia | Southeast Asia | 331689.00 | 1945 | 79832000 | 69.3 | 21929.00 | 22834.00 | Viêt Nam | Socialistic Republic | Trân Duc Luong | 3770 | VN | | YEM | Yemen | Asia | Middle East | 527968.00 | 1918 | 18112000 | 59.8 | 6041.00 | 5729.00 | Al-Yaman | Republic | Ali Abdallah Salih | 1780 | YE | +------+----------------------+-----------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------+----------------------------------+---------+-------+ 51 rows in set (0.00 sec)
このように、 =
で指定した内容に完全一致する行だけが取得できた。では、世界の中で、日本と同じように国名の先頭が 'J' で始まる国はいくつあるだろうか。
テーブルの中から指定条件に部分一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE カラム名 LIKE '合致させたい内容')
=
の代わりにLIKE
を使うことで、完全一致ではなく部分一致でデータを探すことができる。指定したい箇所以外の文字はパーセント(%
)で表記する。たとえば「国名がJではじまる」であれば WHERE Name LIKE 'J%'
とし、「国名がnで終わる」であれば WHERE Name LIKE '%n'
とし、「国名の先頭と末尾以外がapa」であれば、 WHERE Name Like '%apa%'
と指定する。
mysql> SELECT * FROM country WHERE Name LIKE 'J%'; +------+---------+---------------+--------------+-------------+-----------+------------+----------------+------------+------------+--------------+-------------------------+--------------+---------+-------+ | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+---------+---------------+--------------+-------------+-----------+------------+----------------+------------+------------+--------------+-------------------------+--------------+---------+-------+ | JAM | Jamaica | North America | Caribbean | 10990.00 | 1962 | 2583000 | 75.2 | 6871.00 | 6722.00 | Jamaica | Constitutional Monarchy | Elisabeth II | 1530 | JM | | JOR | Jordan | Asia | Middle East | 88946.00 | 1946 | 5083000 | 77.4 | 7526.00 | 7051.00 | Al-Urdunn | Constitutional Monarchy | Abdullah II | 1786 | JO | | JPN | Japan | Asia | Eastern Asia | 377829.00 | -660 | 126714000 | 80.7 | 3787042.00 | 4192638.00 | Nihon/Nippon | Constitutional Monarchy | Akihito | 1532 | JP | +------+---------+---------------+--------------+-------------+-----------+------------+----------------+------------+------------+--------------+-------------------------+--------------+---------+-------+ 3 rows in set (0.00 sec)
J で始まる国は、ジャマイカとヨルダンと日本だけだった。では、同じように国名が 'K' で始まり、かつアジア大陸にある国だけを取ってきてほしい場合はどうすればいいだろう。その場合は、 WHERE Continent = 'Asia'
と WHERE Name LIKE 'K%'
のふたつの条件を組み合わせなければならない。
テーブルの中から複数条件のすべてに一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE 条件 AND 条件)
複数条件を指定したい場合、WHERE
のあとにふたつ以上の条件を AND
でつなげることで指定することができる。WHERE Continent = 'Asia'
と WHERE Name LIKE 'K%'
なら、WHERE Continent = 'Asia' AND Name LIKE 'K%'
(WHERE
はひとつで良い)になる。
mysql> SELECT * FROM country WHERE Name LIKE 'K%' AND continent = 'Asia'; +------+------------+-----------+---------------------------+-------------+-----------+------------+----------------+----------+----------+------------+-----------------------------------+----------------------------------+---------+-------+ | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+------------+-----------+---------------------------+-------------+-----------+------------+----------------+----------+----------+------------+-----------------------------------+----------------------------------+---------+-------+ | KAZ | Kazakstan | Asia | Southern and Central Asia | 2724900.00 | 1991 | 16223000 | 63.2 | 24375.00 | 23383.00 | Qazaqstan | Republic | Nursultan Nazarbajev | 1864 | KZ | | KGZ | Kyrgyzstan | Asia | Southern and Central Asia | 199900.00 | 1991 | 4699000 | 63.4 | 1626.00 | 1767.00 | Kyrgyzstan | Republic | Askar Akajev | 2253 | KG | | KWT | Kuwait | Asia | Middle East | 17818.00 | 1961 | 1972000 | 76.1 | 27037.00 | 30373.00 | Al-Kuwayt | Constitutional Monarchy (Emirate) | Jabir al-Ahmad al-Jabir al-Sabah | 2429 | KW | +------+------------+-----------+---------------------------+-------------+-----------+------------+----------------+----------+----------+------------+-----------------------------------+----------------------------------+---------+-------+ 3 rows in set (0.00 sec)
カザフスタンとキルギスとクウェートが条件に合致した。では、国名の先頭が 'K' もしくは 'P' の国ではどうだろうか。
テーブルの中から複数条件のいずれかまたは両方に一致するデータを取得する(SELECT カラム名 FROM テーブル名 WHERE 条件 OR 条件)
いずれかまたは両方に合致させたい複数条件を指定する場合、WHERE
のあとにふたつ以上の条件を OR
でつなげることで指定することができる。WHERE Name LIKE 'P%'
と WHERE Name LIKE 'K%'
なら、WHERE Name LIKE 'P%' OR Name LIKE 'K%'
(WHERE
はひとつで良い)になる。
mysql> SELECT Name, Continent FROM country WHERE Name LIKE 'P%' OR Name LIKE 'K%'; +------------------+---------------+ | Name | Continent | +------------------+---------------+ | Kazakstan | Asia | | Kenya | Africa | | Kyrgyzstan | Asia | | Kiribati | Oceania | | Kuwait | Asia | | Pakistan | Asia | | Panama | North America | | Pitcairn | Oceania | | Peru | South America | | Philippines | Asia | | Palau | Oceania | | Papua New Guinea | Oceania | | Poland | Europe | | Puerto Rico | North America | | Portugal | Europe | | Paraguay | South America | | Palestine | Asia | +------------------+---------------+ 17 rows in set (0.00 sec)
無事取得することができた。さらにアジア大陸の国だけに絞る場合、 Continent = 'Asia'
を条件に追加する必要がある。大陸の指定は、Pで始まる国でもKで始まる国でも絞り込みたい条件なので、 OR
で追加することはできない。そのまま AND
でつなげた場合、以下のようになる。
mysql> SELECT Name, Continent FROM country WHERE Name LIKE 'P%' OR Name LIKE 'K%' AND Continent = 'Asia'; +------------------+---------------+ | Name | Continent | +------------------+---------------+ | Kazakstan | Asia | | Kyrgyzstan | Asia | | Kuwait | Asia | | Pakistan | Asia | | Panama | North America | | Pitcairn | Oceania | | Peru | South America | | Philippines | Asia | | Palau | Oceania | | Papua New Guinea | Oceania | | Poland | Europe | | Puerto Rico | North America | | Portugal | Europe | | Paraguay | South America | | Palestine | Asia | +------------------+---------------+ 15 rows in set (0.00 sec)
Kで始まる国についてはアジア大陸だけに絞り込まれているが、Pで始まる国については絞り込めていない。これは、 WHERE Name LIKE 'P%' OR Name LIKE 'K%' AND Continent = 'Asia'
という条件が、「国名がPで始まる」もしくは「国名がKで始まり、かつ大陸がアジア」という意味になってしまっているからだ。これを「国名がPで始まる」または「国名がKで始まる」、かつ「大陸がアジア」としたい場合、またはの条件のほうをカッコで囲み、WHERE ( Name LIKE 'P%' OR Name LIKE 'K%' ) AND Continent = 'Asia'
のようにする。
mysql> SELECT Name, Continent FROM country WHERE ( Name LIKE 'P%' OR Name LIKE 'K%' ) AND Continent = 'Asia'; +-------------+-----------+ | Name | Continent | +-------------+-----------+ | Kazakstan | Asia | | Kyrgyzstan | Asia | | Kuwait | Asia | | Pakistan | Asia | | Philippines | Asia | | Palestine | Asia | +-------------+-----------+ 6 rows in set (0.00 sec)
無事絞り込めた。ところで国名がアルファベット順になっていないので、これを並び替えたい。
テーブルの取得結果をカラムの内容で並び替える(SELECT カラム名 FROM テーブル名 ORDER BY カラム名 昇順または降順)
SELECT での取得結果を並び替えて表示したい場合、 ORDER BY カラム名
に続けて、昇順(ASC)または降順(DESC)を指定すれば良い(指定しなかった場合昇順になる)。
mysql> SELECT Name, Continent FROM country WHERE ( Name LIKE 'P%' OR Name LIKE 'K%' ) AND Continent = 'Asia' ORDER BY Name ASC; +-------------+-----------+ | Name | Continent | +-------------+-----------+ | Kazakstan | Asia | | Kuwait | Asia | | Kyrgyzstan | Asia | | Pakistan | Asia | | Palestine | Asia | | Philippines | Asia | +-------------+-----------+ 6 rows in set (0.00 sec)
アルファベットの昇順になった。これを応用して、たとえば世界の面積の大きな国のランキングを見ることもできる。
mysql> SELECT Name, SurfaceArea FROM country ORDER BY SurfaceArea DESC LIMIT 10; +--------------------+-------------+ | Name | SurfaceArea | +--------------------+-------------+ | Russian Federation | 17075400.00 | | Antarctica | 13120000.00 | | Canada | 9970610.00 | | China | 9572900.00 | | United States | 9363520.00 | | Brazil | 8547403.00 | | Australia | 7741220.00 | | India | 3287263.00 | | Argentina | 2780400.00 | | Kazakstan | 2724900.00 | +--------------------+-------------+ 10 rows in set (0.00 sec)
テーブルの取得条件に以上、以下を使う(SELECT カラム名 FROM テーブル名 WHERE カラム名 >= 数値 OR カラム名 <= 数値)
>=
,<=
,>
,<
を使うことで、以上、以下、より大きい、未満、を指定することができる。たとえば平均余命(LifeExpectancy)が80歳以上の国を取ってくる場合、 WHERE LifeExpectancy >= 80
のように指定する。
mysql> SELECT Name, LifeExpectancy FROM country WHERE LifeExpectancy >= 80; +------------+----------------+ | Name | LifeExpectancy | +------------+----------------+ | Andorra | 83.5 | | Japan | 80.7 | | Macao | 81.6 | | Singapore | 80.1 | | San Marino | 81.1 | +------------+----------------+ 5 rows in set (0.00 sec)
逆に平均余命が40歳以下の国は、以下のように取ってくることができる。
mysql> SELECT Name, LifeExpectancy FROM country WHERE LifeExpectancy <= 40; +------------+----------------+ | Name | LifeExpectancy | +------------+----------------+ | Angola | 38.3 | | Botswana | 39.3 | | Mozambique | 37.5 | | Malawi | 37.6 | | Rwanda | 39.3 | | Zambia | 37.2 | | Zimbabwe | 37.8 | +------------+----------------+ 7 rows in set (0.00 sec)
テーブルの全件数を取得する(SELECT COUNT(*) FROM テーブル名)
特定のテーブルで管理されているデータの全件数が取得したい場合、 SELECT * FROM テーブル名
で全件取得することで確認することもできるが、取得対象カラム名に COUNT(*)
を指定することで、もっとスマートに件数だけを取ってきてもらうこともできる。
mysql> SELECT COUNT(*) FROM country; +----------+ | COUNT(*) | +----------+ | 239 | +----------+ 1 row in set (0.00 sec)
COUNT(*)
は COUNT(1)
と表記しても良い。
mysql> SELECT COUNT(1) FROM country; +----------+ | COUNT(1) | +----------+ | 239 | +----------+ 1 row in set (0.03 sec)
では、大陸別の国の数を取ってきてみたい。大陸(Continent)でまとめることができれば、数えることができそうだ。
テーブルの内容を特定のカラムの内容でグループ分けする(SELECT * FROM テーブル名 GROUP BY カラム名)
GROUP BY カラム名
を指定することで、指定したカラムの内容でまとめた結果を取得することができる。これは主に COUNT()
などの複数のカラムの内容をまとめるコマンドと併用する。併用しなかった場合、以下のようにまとめられたうちの1件だけが表示される。
mysql> SELECT Name, Continent FROM country GROUP BY Continent; +----------------+---------------+ | Name | Continent | +----------------+---------------+ | Afghanistan | Asia | | Albania | Europe | | Aruba | North America | | Angola | Africa | | American Samoa | Oceania | | Antarctica | Antarctica | | Argentina | South America | +----------------+---------------+ 7 rows in set (0.00 sec)
ここで COUNT(*)
を併用すると、以下のようになる。
mysql> SELECT COUNT(1), Continent FROM country GROUP BY Continent; +----------+---------------+ | COUNT(1) | Continent | +----------+---------------+ | 51 | Asia | | 46 | Europe | | 37 | North America | | 58 | Africa | | 28 | Oceania | | 5 | Antarctica | | 14 | South America | +----------+---------------+ 7 rows in set (0.00 sec)
アフリカ大陸の国が一番多いことがわかった。COUNT()
と同じように、GROUP BY
と組み合わせて取得結果を操作するコマンドは他にもある。
指定されたカラムの最大値、最小値を取得する(SELECT MAX(カラム名), MIN(カラム名) FROM テーブル名 GROUP BY カラム名)
MAX()
とMIN()
を使うことで、最大値と最小値を取得することができる(MAX()
とMIN()
はもちろん個別に使うこともできる)。
mysql> SELECT MAX(SurfaceArea), MIN(SurfaceArea), Continent FROM country GROUP BY Continent; +------------------+------------------+---------------+ | MAX(SurfaceArea) | MIN(SurfaceArea) | Continent | +------------------+------------------+---------------+ | 9572900.00 | 18.00 | Asia | | 17075400.00 | 0.40 | Europe | | 9970610.00 | 53.00 | North America | | 2505813.00 | 78.00 | Africa | | 7741220.00 | 12.00 | Oceania | | 13120000.00 | 59.00 | Antarctica | | 8547403.00 | 12173.00 | South America | +------------------+------------------+---------------+ 7 rows in set (0.00 sec)
アジア最大の国は9572900.00平方km、最小の国は18.00平方kmであることがわかった。(それぞれ =
で指定して国名を調べてみても面白いかもしれない)
指定されたカラムに登録されている内容の合計値を取得する(SELECT SUM(カラム名) FROM テーブル名)
SUM(カラム名)
を使うことで、合計値が取得できる。
mysql> SELECT SUM(SurfaceArea), Continent FROM country GROUP BY Continent; +------------------+---------------+ | SUM(SurfaceArea) | Continent | +------------------+---------------+ | 31881005.00 | Asia | | 23049133.90 | Europe | | 24214470.00 | North America | | 30250377.00 | Africa | | 8564294.00 | Oceania | | 13132101.00 | Antarctica | | 17864926.00 | South America | +------------------+---------------+ 7 rows in set (0.01 sec)
各大陸の国の面積の合計値(=各大陸の面積?)が取得できた。
指定されたカラムに登録されている内容の文字数を取得する(SELECT LENGTH(カラム名) FROM テーブル名)
LENGTH(カラム名)
を指定することで、その内容の文字数を取得することができる。SUM()
と組み合わせて、以下のようなこともできる。
mysql> SELECT SUM(LENGTH(Name)), Continent FROM country GROUP BY Continent; +-------------------+---------------+ | SUM(LENGTH(Name)) | Continent | +-------------------+---------------+ | 396 | Asia | | 425 | Europe | | 446 | North America | | 547 | Africa | | 359 | Oceania | | 127 | Antarctica | | 113 | South America | +-------------------+---------------+ 7 rows in set (0.01 sec)
各大陸の国名の英語表記名の文字数合計が取得できた。(国名が20文字以上の国の一覧や、5文字以下の国一覧を取ってきても面白いかもしれない)
指定されたカラムに登録されている内容を重複を取り除いて表示する(SELECT DISTINCT カラム名 FROM テーブル名)
DISTINCT カラム名
を使うことで、重複を取り除いた結果を取得することができる。
mysql> SELECT DISTINCT Continent FROM country; +---------------+ | Continent | +---------------+ | North America | | Asia | | Africa | | Europe | | South America | | Oceania | | Antarctica | +---------------+ 7 rows in set (0.00 sec)
大陸名(Continent)を指定することで、その内容を重複なしで取ってこれた。
複数のカラムの内容や文字列を結合して結果に含める(SELECT CONCAT(文字列やカラム名, 文字列やカラム名, ...) FROM テーブル名)
CONCAT()
を使うことで、複数の文字の結合をすることができる。'Hello!'
' '
'World!'
の3つの文字列を組み合わせるには、以下のようにする。
mysql> SELECT CONCAT('Hello!', ' ', 'World!'); +---------------------------------+ | CONCAT('Hello!', ' ', 'World!') | +---------------------------------+ | Hello! World! | +---------------------------------+ 1 row in set (0.01 sec)
文字列の代わりにカラム名を指定することもできる。たとえば国名と大陸名をくっつけて表示したい場合、以下のようにする。
mysql> SELECT CONCAT(Name, ' (', Continent, ')') FROM country LIMIT 10; +--------------------------------------+ | CONCAT(Name, ' (', Continent, ')') | +--------------------------------------+ | Aruba (North America) | | Afghanistan (Asia) | | Angola (Africa) | | Anguilla (North America) | | Albania (Europe) | | Andorra (Europe) | | Netherlands Antilles (North America) | | United Arab Emirates (Asia) | | Argentina (South America) | | Armenia (Asia) | +--------------------------------------+ 10 rows in set (0.00 sec)
CONCAT(Name, ' (', Continent, ')')
の表示が少し見づらいので、これに別名をつけてみたい。
取得結果に別名をつける(SELECT 取得結果 AS 別名)
AS 別名
を追加することで、別名をつけることができる。
mysql> SELECT CONCAT(Name, ' (', Continent, ')') AS NameContinent FROM country LIMIT 10; +--------------------------------------+ | NameContinent | +--------------------------------------+ | Aruba (North America) | | Afghanistan (Asia) | | Angola (Africa) | | Anguilla (North America) | | Albania (Europe) | | Andorra (Europe) | | Netherlands Antilles (North America) | | United Arab Emirates (Asia) | | Argentina (South America) | | Armenia (Asia) | +--------------------------------------+ 10 rows in set (0.00 sec)
この別名は、並び替えのカラム名にも指定することができる。
mysql> SELECT CONCAT(Name, ' (', Continent, ')') AS NameContinent FROM country ORDER BY NameContinent LIMIT 10; +-------------------------------------+ | NameContinent | +-------------------------------------+ | Afghanistan (Asia) | | Albania (Europe) | | Algeria (Africa) | | American Samoa (Oceania) | | Andorra (Europe) | | Angola (Africa) | | Anguilla (North America) | | Antarctica (Antarctica) | | Antigua and Barbuda (North America) | | Argentina (South America) | +-------------------------------------+ 10 rows in set (0.01 sec)
ふたつのテーブルを組み合わせて結果を取得する
さて、ここまで一通りの取得操作を見てきた。これで、ひとつのテーブルからデータを取ってくることは、一通りできるようになったと思う。では、ここからはふたつのテーブルの内容を組み合わせて表示する方法を説明していく。すこし複雑になるので、わからなくなったら、無理せずまたここに戻ってきてほしい。
いままで country
テーブルを使って説明してきたが、 world
データベースの中には他にもテーブルがある。
mysql> SHOW TABLES; +-----------------+ | Tables_in_world | +-----------------+ | city | | country | | countrylanguage | +-----------------+ 3 rows in set (0.00 sec)
city
を見てみよう。
mysql> DESC city; +-------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+----------------+ | ID | int(11) | NO | PRI | NULL | auto_increment | | Name | char(35) | NO | | | | | CountryCode | char(3) | NO | MUL | | | | District | char(20) | NO | | | | | Population | int(11) | NO | | 0 | | +-------------+----------+------+-----+---------+----------------+ 5 rows in set (0.03 sec)
ID番号、名前、国コード、県名、人口が登録されているようだ。では、試しに都市名(Name)が 'Tripoli'
(トリポリ)になっている都市を探してみよう。
mysql> select * from city where Name = 'Tripoli'; +------+---------+-------------+-----------+------------+ | ID | Name | CountryCode | District | Population | +------+---------+-------------+-----------+------------+ | 2439 | Tripoli | LBN | al-Shamal | 240000 | | 2441 | Tripoli | LBY | Tripoli | 1682000 | +------+---------+-------------+-----------+------------+ 2 rows in set (0.00 sec)
該当する都市が2件見つかった。それぞれ CountryCode
が LBN, LBY となっているが、これだけでは国名がはっきりしない*6。国コードを使って、以下のように個別に調べてやることもできる。
mysql> select * from country WHERE Code = 'LBN'; +------+---------+-----------+-------------+-------------+-----------+------------+----------------+----------+----------+-----------+----------------+---------------+---------+-------+ | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+---------+-----------+-------------+-------------+-----------+------------+----------------+----------+----------+-----------+----------------+---------------+---------+-------+ | LBN | Lebanon | Asia | Middle East | 10400.00 | 1941 | 3282000 | 71.3 | 17121.00 | 15129.00 | Lubnan | Republic | Émile Lahoud | 2438 | LB | +------+---------+-----------+-------------+-------------+-----------+------------+----------------+----------+----------+-----------+----------------+---------------+---------+-------+ 1 row in set (0.00 sec)
ふたつのテーブルに該当する行を結合して取得する(INNER JOIN)
LBN はレバノンだとわかった。しかし、こうやっていちいち該当するデータを別のテーブルから検索してくるのは手間がかかりすぎる。そこで、city
と country
の内容を結合して表示したい。結合するには、 INNER JOIN
を使用する。city
テーブルに対して country
テーブルを結合するので、 SELECT * FROM city INNER JOIN country WHERE Name = 'Tripoli';
とする。これを実行すると以下のようになる。
mysql> SELECT * FROM city INNER JOIN country WHERE Name = 'Tripoli'; ERROR 1052 (23000): Column 'Name' in where clause is ambiguous
エラーメッセージの中の ambiguous
とは「曖昧な」という意味で、エラーメッセージ全体では「WHERE の中に書いてある 'Name' というカラム名は曖昧だ」と言われている。どういうことだろうか。それぞれのテーブルをよく見てみよう。
mysql> DESC city; +-------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+----------------+ | ID | int(11) | NO | PRI | NULL | auto_increment | | Name | char(35) | NO | | | | | CountryCode | char(3) | NO | MUL | | | | District | char(20) | NO | | | | | Population | int(11) | NO | | 0 | | +-------------+----------+------+-----+---------+----------------+ 5 rows in set (0.01 sec) mysql> DESC country; +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ | Code | char(3) | NO | PRI | | | | Name | char(52) | NO | | | | | Continent | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO | | Asia | | | Region | char(26) | NO | | | | | SurfaceArea | float(10,2) | NO | | 0.00 | | | IndepYear | smallint(6) | YES | | NULL | | | Population | int(11) | NO | | 0 | | | LifeExpectancy | float(3,1) | YES | | NULL | | | GNP | float(10,2) | YES | | NULL | | | GNPOld | float(10,2) | YES | | NULL | | | LocalName | char(45) | NO | | | | | GovernmentForm | char(45) | NO | | | | | HeadOfState | char(60) | YES | | NULL | | | Capital | int(11) | YES | | NULL | | | Code2 | char(2) | NO | | | | +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ 15 rows in set (0.00 sec)
Name カラムに注目しよう。両方のテーブルに 'Name' カラムがあることがわかるはずだ。「曖昧だ」というのはつまり、「city テーブルの中の Name カラムなのか、country テーブルの中の Name カラムなのかが曖昧だ」という意味なのだ。どちらのテーブルの Name カラムなのか、はっきりと指定してやる必要がある。指定したいのは city
テーブルなので、city.Name
のように書くことができる。SELECT * FROM city INNER JOIN country WHERE city.Name = 'Tripoli';
これを実行すると、以下のようになる。
mysql> SELECT * FROM city INNER JOIN country WHERE city.Name = 'Tripoli'; +------+---------+-------------+-----------+------------+------+----------------------------------------------+---------------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------------+--------------------------------------+---------+-------+ | ID | Name | CountryCode | District | Population | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+---------+-------------+-----------+------------+------+----------------------------------------------+---------------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------------+--------------------------------------+---------+-------+ | 2439 | Tripoli | LBN | al-Shamal | 240000 | ABW | Aruba | North America | Caribbean | 193.00 | NULL | 103000 | 78.4 | 828.00 | 793.00 | Aruba | Nonmetropolitan Territory of The Netherlands | Beatrix | 129 | AW | | 2439 | Tripoli | LBN | al-Shamal | 240000 | AFG | Afghanistan | Asia | Southern and Central Asia | 652090.00 | 1919 | 22720000 | 45.9 | 5976.00 | NULL | Afganistan/Afqanestan | Islamic Emirate | Mohammad Omar | 1 | AF | | 2439 | Tripoli | LBN | al-Shamal | 240000 | AGO | Angola | Africa | Central Africa | 1246700.00 | 1975 | 12878000 | 38.3 | 6648.00 | 7984.00 | Angola | Republic | José Eduardo dos Santos | 56 | AO | (中略) | 2441 | Tripoli | LBY | Tripoli | 1682000 | ZAF | South Africa | Africa | Southern Africa | 1221037.00 | 1910 | 40377000 | 51.1 | 116729.00 | 129092.00 | South Africa | Republic | Thabo Mbeki | 716 | ZA | | 2441 | Tripoli | LBY | Tripoli | 1682000 | ZMB | Zambia | Africa | Eastern Africa | 752618.00 | 1964 | 9169000 | 37.2 | 3377.00 | 3922.00 | Zambia | Republic | Frederick Chiluba | 3162 | ZM | | 2441 | Tripoli | LBY | Tripoli | 1682000 | ZWE | Zimbabwe | Africa | Eastern Africa | 390757.00 | 1980 | 11669000 | 37.8 | 5951.00 | 8670.00 | Zimbabwe | Republic | Robert G. Mugabe | 4068 | ZW | +------+---------+-------------+-----------+------------+------+----------------------------------------------+---------------+---------------------------+-------------+-----------+------------+----------------+------------+------------+----------------------------------------------+----------------------------------------------+--------------------------------------+---------+-------+ 478 rows in set (0.01 sec)
またも画面が文字で埋まってしまった。トリポリという都市は2つしかなかったはずなのに、なぜ478件も出てきてしまったのだろうか。それは、結合の対象にするカラム名を指定していないからだ。結合対象のカラムを指定していない場合、データベースの管理人は以下のように考えてしまう。
- city テーブルから、Name が Tripoli になっている行を取ってくる。2件だった。
- country テーブルから、全件取ってくる。239件だった。
- 結合対象カラムが指定されていないので、cityの結果1件ずつに、それぞれ239件のcountryの結果を組み合わせよう。2件 x 239件 = 478件の結果ができた。
これは望んだ結果ではないので、コマンドを修正しよう。city.CountryCode
と country.Code
を結合してほしいので、指定を追加する。 INNER JOIN テーブル名 ON 結合対象指定
と入力するので、 SELECT * FROM city INNER JOIN country ON city.CountryCode = country.Code WHERE city.Name = 'Tripoli'
となった。
mysql> SELECT * FROM city INNER JOIN country ON city.CountryCode = country.Code WHERE city.Name = 'Tripoli'; +------+---------+-------------+-----------+------------+------+------------------------+-----------+-----------------+-------------+-----------+------------+----------------+----------+----------+-----------+-------------------+--------------------+---------+-------+ | ID | Name | CountryCode | District | Population | Code | Name | Continent | Region | SurfaceArea | IndepYear | Population | LifeExpectancy | GNP | GNPOld | LocalName | GovernmentForm | HeadOfState | Capital | Code2 | +------+---------+-------------+-----------+------------+------+------------------------+-----------+-----------------+-------------+-----------+------------+----------------+----------+----------+-----------+-------------------+--------------------+---------+-------+ | 2439 | Tripoli | LBN | al-Shamal | 240000 | LBN | Lebanon | Asia | Middle East | 10400.00 | 1941 | 3282000 | 71.3 | 17121.00 | 15129.00 | Lubnan | Republic | Émile Lahoud | 2438 | LB | | 2441 | Tripoli | LBY | Tripoli | 1682000 | LBY | Libyan Arab Jamahiriya | Africa | Northern Africa | 1759540.00 | 1951 | 5605000 | 75.5 | 44806.00 | 40562.00 | Libiya | Socialistic State | Muammar al-Qadhafi | 2441 | LY | +------+---------+-------------+-----------+------------+------+------------------------+-----------+-----------------+-------------+-----------+------------+----------------+----------+----------+-----------+-------------------+--------------------+---------+-------+ 2 rows in set (0.00 sec)
さきほどよりは平和な結果になった。しかし横長で見えづらいので、見たい情報だけに絞って表示しよう。 *
の部分を見たいカラムの指定に変更する。だからといってただ単にカラム名を記述してしまうと、以下のようになってしまう。
mysql> SELECT ID, Name, CountryCode, District, Population, Name FROM city INNER JOIN country ON city.CountryCode = country.Code WHERE city.Name = 'Tripoli'; ERROR 1052 (23000): Column 'Name' in field list is ambiguous
また「曖昧だ」とエラーメッセージが出てくるので、同じようにテーブル名込みで指定しよう。
mysql> SELECT city.ID, city.Name, city.CountryCode, city.District, city.Population, country.Name FROM city INNER JOIN country ON city.CountryCode = country.Code WHERE city.Name = 'Tripoli'; +------+---------+-------------+-----------+------------+------------------------+ | ID | Name | CountryCode | District | Population | Name | +------+---------+-------------+-----------+------------+------------------------+ | 2439 | Tripoli | LBN | al-Shamal | 240000 | Lebanon | | 2441 | Tripoli | LBY | Tripoli | 1682000 | Libyan Arab Jamahiriya | +------+---------+-------------+-----------+------------+------------------------+ 2 rows in set (0.00 sec)
しかし、結果の Name
にテーブル名が含まれていないので、別名をつけてやることにする。
mysql> SELECT city.ID, city.Name AS CityName, city.CountryCode, city.District, city.Population, country.Name AS CountryName FROM city INNER JOIN country ON city.CountryCode = country.Code WHERE city.Name = 'Tripoli'; +------+----------+-------------+-----------+------------+------------------------+ | ID | CityName | CountryCode | District | Population | CountryName | +------+----------+-------------+-----------+------------+------------------------+ | 2439 | Tripoli | LBN | al-Shamal | 240000 | Lebanon | | 2441 | Tripoli | LBY | Tripoli | 1682000 | Libyan Arab Jamahiriya | +------+----------+-------------+-----------+------------+------------------------+ 2 rows in set (0.01 sec)
また、別名と組み合わせることはできないが、 テーブル名.*
を使ってカラム指定を省略することができる。*
を使っていないテーブルのカラムには、別名をつけても問題ない。
mysql> SELECT city.*, country.Name AS CountryName FROM city INNER JOIN country ON city.CountryCode = country.Code WHERE city.Name = 'Tripoli'; +------+---------+-------------+-----------+------------+------------------------+ | ID | Name | CountryCode | District | Population | CountryName | +------+---------+-------------+-----------+------------+------------------------+ | 2439 | Tripoli | LBN | al-Shamal | 240000 | Lebanon | | 2441 | Tripoli | LBY | Tripoli | 1682000 | Libyan Arab Jamahiriya | +------+---------+-------------+-----------+------------+------------------------+ 2 rows in set (0.00 sec)
ふたつのテーブルに該当する行と、片方にだけある行を結合して取得する(LEFT OUTER JOIN, RIGHT OUTER JOIN)
ところで、 countryLanguage
テーブルを見てみよう。
mysql> DESC countryLanguage; +-------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+-------+ | CountryCode | char(3) | NO | PRI | | | | Language | char(30) | NO | PRI | | | | IsOfficial | enum('T','F') | NO | | F | | | Percentage | float(4,1) | NO | | 0.0 | | +-------------+---------------+------+-----+---------+-------+ 4 rows in set (0.01 sec)
CountryCode
が 'JPN'
になっているレコードを見てみると、以下のようになっている。
mysql> select * from countryLanguage WHERE CountryCode = 'JPN'; +-------------+----------------------+------------+------------+ | CountryCode | Language | IsOfficial | Percentage | +-------------+----------------------+------------+------------+ | JPN | Ainu | F | 0.0 | | JPN | Chinese | F | 0.2 | | JPN | English | F | 0.1 | | JPN | Japanese | T | 99.1 | | JPN | Korean | F | 0.5 | | JPN | Philippene Languages | F | 0.1 | +-------------+----------------------+------------+------------+ 6 rows in set (0.01 sec)
日本で話されている言語と、話者の割合が管理されていることがわかる。 Language
を指定すれば、その言語が話されている国と割合がわかる。
mysql> select * from countryLanguage WHERE Language = 'English'; +-------------+----------+------------+------------+ | CountryCode | Language | IsOfficial | Percentage | +-------------+----------+------------+------------+ | ABW | English | F | 9.5 | | AIA | English | T | 0.0 | | ANT | English | F | 7.8 | (中略) | WSM | English | T | 0.6 | | ZAF | English | T | 8.5 | | ZWE | English | T | 2.2 | +-------------+----------+------------+------------+ 60 rows in set (0.01 sec)
英語が60カ国で話されていることがわかった。では、国の一覧と、その国の英語話者の割合を一覧にしてみよう。INNER JOIN で、 country
テーブルの一覧と countryLanguage
テーブルを Language = 'English'
で絞り込んだ結果一覧とを結合する。
mysql> SELECT country.Code, country.Name AS CountryName, countryLanguage.Language, countryLanguage.IsOfficial, countryLanguage.Percentage FROM country INNER JOIN countryLanguage ON country.Code = countryLanguage.CountryCode WHERE Language = 'English'; +------+--------------------------------------+----------+------------+------------+ | Code | CountryName | Language | IsOfficial | Percentage | +------+--------------------------------------+----------+------------+------------+ | ABW | Aruba | English | F | 9.5 | | AIA | Anguilla | English | T | 0.0 | | ANT | Netherlands Antilles | English | F | 7.8 | (中略) | WSM | Samoa | English | T | 0.6 | | ZAF | South Africa | English | T | 8.5 | | ZWE | Zimbabwe | English | T | 2.2 | +------+--------------------------------------+----------+------------+------------+ 60 rows in set (0.01 sec)
たしかに結果一覧が出たが、一覧には、英語を話していない国も一緒に含めたい。INNER JOIN では、結合するふたつのテーブル両方にある行しか結果一覧に含めない。そこで、この場合には OUTER JOIN を使用する。
mysql> SELECT country.Code, country.Name AS CountryName, countryLanguage.Language, countryLanguage.IsOfficial, countryLanguage.Percentage FROM country LEFT JOIN countryLanguage ON country.Code = countryLanguage.CountryCode AND countryLanguage.Language = 'English'; +------+----------------------------------------------+----------+------------+------------+ | Code | CountryName | Language | IsOfficial | Percentage | +------+----------------------------------------------+----------+------------+------------+ | ABW | Aruba | English | F | 9.5 | | AFG | Afghanistan | NULL | NULL | NULL | | AGO | Angola | NULL | NULL | NULL | (中略) | ZAF | South Africa | English | T | 8.5 | | ZMB | Zambia | NULL | NULL | NULL | | ZWE | Zimbabwe | English | T | 2.2 | +------+----------------------------------------------+----------+------------+------------+ 239 rows in set (0.00 sec)
また、この場合には countryLanguage.Language = 'English'
の条件を WHERE
に含めず、LEFT JOIN 手^ブル名 ON
の後に入力する。 WHERE
に含めた場合は、以下のようになる。
mysql> SELECT country.Code, country.Name AS CountryName, countryLanguage.Language, countryLanguage.IsOfficial, countryLanguage.Percentage FROM country LEFT JOIN countryLanguage ON country.Code = countryLanguage.CountryCode WHERE countryLanguage.Language = 'English'; +------+--------------------------------------+----------+------------+------------+ | Code | CountryName | Language | IsOfficial | Percentage | +------+--------------------------------------+----------+------------+------------+ | ABW | Aruba | English | F | 9.5 | | AIA | Anguilla | English | T | 0.0 | | ANT | Netherlands Antilles | English | F | 7.8 | (中略) | WSM | Samoa | English | T | 0.6 | | ZAF | South Africa | English | T | 8.5 | | ZWE | Zimbabwe | English | T | 2.2 | +------+--------------------------------------+----------+------------+------------+ 60 rows in set (0.00 sec)
結果が60件しか出てこず、 INNER JOIN
と同じになっている。これは、上のSQLを管理人が以下のように理解するからである*7。
- country テーブルから全件を取得する。結果は239件。
- countryLanguage テーブルから全件を取得する。結果は984件。
- 1と2の結果一覧を
country.Code = countryLanguage.CountryCode
の条件で結合する。 - 3の結果のうち、
countryLanguage.Language = 'English'
に該当する行だけに絞り込む。結果は60件。
これを ON に書くことで、以下のように解釈してもらえます。
- country テーブルから全件を取得する。結果は239件。
- countryLanguage テーブルのうち
countryLanguage.Language = 'English'
に該当する行だけに絞り込む。結果は60件。 - 1に2を
country.Code = countryLanguage.CountryCode
の条件で結合する。1のデータのうち2に該当する行が無いものも、結合結果に含める。結果は239件。
A LEFT JOIN B
の場合には A にしかないデータも結果に含まれ、 A RIGHT JOIN B
の場合には B にしかないデータも結果に含まれる。LEFT と RIGHT とでは、このテーブルの結合の方向が異なる。
結合の説明はここまで。
テーブルにデータを追加する(INSERT INTO テーブル名 ( カラム名 ) VALUES ( データ ))
世界に新しい国ができたとか、country
テーブルに不足しているデータがあった場合、データを追加する必要がでてくる。Excel では空白の行にデータを追加するが、MySQL ではコマンドでデータを追加する。追加先のテーブルを確認しよう。
mysql> DESC country; +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ | Code | char(3) | NO | PRI | | | | Name | char(52) | NO | | | | | Continent | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO | | Asia | | | Region | char(26) | NO | | | | | SurfaceArea | float(10,2) | NO | | 0.00 | | | IndepYear | smallint(6) | YES | | NULL | | | Population | int(11) | NO | | 0 | | | LifeExpectancy | float(3,1) | YES | | NULL | | | GNP | float(10,2) | YES | | NULL | | | GNPOld | float(10,2) | YES | | NULL | | | LocalName | char(45) | NO | | | | | GovernmentForm | char(45) | NO | | | | | HeadOfState | char(60) | YES | | NULL | | | Capital | int(11) | YES | | NULL | | | Code2 | char(2) | NO | | | | +----------------+---------------------------------------------------------------------------------------+------+-----+---------+-------+ 15 rows in set (0.00 sec)
追加するデータを用意して、INSERT コマンドを入力する。ここでは、オーランド諸島自治領が突然独立したものとして、データを追加する*8。
mysql> INSERT INTO country ( Code, Name, Continent, Region, SurfaceArea, IndepYear, Population, LifeExpectancy, GNP, GNPOld, LocalName, GovernmentForm, HeadOfState, Capital, Code2 ) VALUES ( 'ALA', 'Aland Islands', 'Europe', 'Nordic Countries', 13517.00, 1920, 28700, 82.5, 0, 0, 'Landskapet Åland', 'Parliamentary System', 'Sauli Väinämö Niinistö', null, 'AX' ); Query OK, 1 row affected (0.02 sec)
追加した結果を SELECT して確認する。
mysql> SELECT * FROM country WHERE Code = 'ALA'\G *************************** 1. row *************************** Code: ALA Name: Aland Islands Continent: Europe Region: Nordic Countries SurfaceArea: 13517.00 IndepYear: 1920 Population: 28700 LifeExpectancy: 82.5 GNP: 0.00 GNPOld: 0.00 LocalName: Landskapet Åland GovernmentForm: Parliamentary System HeadOfState: Sauli Väinämö Niinistö Capital: NULL Code2: AX 1 row in set (0.00 sec)
このままでは首都のマリエハムンが登録されていないので、Capital のデータを更新して、首都を設定しよう。DESC country;
の結果を見ればわかるように、 Capital
カラムは int(11)
というカラムタイプになっている。これは「11桁の数字」という意味で、スウェーデンの場合、以下のようになっている。
mysql> SELECT Code, Name, Capital FROM country WHERE Name = 'Sweden'; +------+--------+---------+ | Code | Name | Capital | +------+--------+---------+ | SWE | Sweden | 3048 | +------+--------+---------+ 1 row in set (0.00 sec)
この 3048
は、以下のように city
テーブルの ID
カラムの番号を意味している。
mysql> select * from city where ID=3048; +------+-----------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+-----------+-------------+----------+------------+ | 3048 | Stockholm | SWE | Lisboa | 750348 | +------+-----------+-------------+----------+------------+ 1 row in set (0.00 sec)
オーランド諸島の首都マリエハムンを city テーブルで検索すると、以下のようになっている。
mysql> select * from city where Name='Mariehamn'; Empty set (0.01 sec)
無い。city
テーブルにも追加する必要がある。
mysql> desc city; +-------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+----------------+ | ID | int(11) | NO | PRI | NULL | auto_increment | | Name | char(35) | NO | | | | | CountryCode | char(3) | NO | MUL | | | | District | char(20) | NO | | | | | Population | int(11) | NO | | 0 | | +-------------+----------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)
確認すると、 city.ID
には auto_increment
という記載がある。これは「自動的に最大値+1を設定する」という意味で、新規にデータを追加した場合、何も指定しなければ最大値+1を設定してくれるようになっている。INSERT では基本的に ID
は指定せず、以下のようにする。
mysql> INSERT INTO city ( Name, CountryCode, District, Population ) VALUES ( 'Mariehamn', 'ALA', 'Aland', 11186 ); Query OK, 1 row affected (0.03 sec)
追加結果を確認する。
mysql> select * from city where Name='Mariehamn'; +------+-----------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+-----------+-------------+----------+------------+ | 4080 | Mariehamn | ALA | Aland | 11186 | +------+-----------+-------------+----------+------------+ 1 row in set (0.00 sec)
ID
は 4080
が割り当てられている。 これで、country
テーブルの Capital
を更新する準備ができた。
テーブルのデータを更新する(UPDATE テーブル名 SET カラム名 = 変更内容 WHERE 条件)
INSERT で追加したオーランド諸島の首都IDを、新規に追加した city.ID
である 4080
で更新する。更新前、データは以下のように NULL
(空データ)になっている。
mysql> SELECT * FROM country WHERE Code = 'ALA'\G *************************** 1. row *************************** Code: ALA Name: Aland Islands Continent: Europe Region: Nordic Countries SurfaceArea: 13517.00 IndepYear: 1920 Population: 28700 LifeExpectancy: 82.5 GNP: 0.00 GNPOld: 0.00 LocalName: Landskapet Åland GovernmentForm: Parliamentary System HeadOfState: Sauli Väinämö Niinistö Capital: NULL Code2: AX 1 row in set (0.00 sec)
これを更新する。
mysql> UPDATE country SET Capital = 4080 WHERE Code = 'ALA'; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0
更新結果を確認する。
mysql> SELECT Code, Name, Capital FROM country WHERE Code = 'ALA'; +------+---------------+---------+ | Code | Name | Capital | +------+---------------+---------+ | ALA | Aland Islands | 4080 | +------+---------------+---------+ 1 row in set (0.00 sec)
UPDATE 時に WHERE
で条件を指定しなかった場合、 country
テーブルの全データが更新されてしまうので、意図していなければ気をつけてコマンドを入力しよう。実行した場合、以下のようになる。
mysql> UPDATE country SET Capital = 4080; Query OK, 240 row affected (0.01 sec) Rows matched: 240 Changed: 240 Warnings: 0
影響を受けた行が意図せず240行になっている。
データを削除する(DELETE FROM テーブル名 WHERE 条件)
先程追加したオーランド諸島のデータを削除してみよう。実施する前に、対象のデータを確認する。
mysql> SELECT * FROM country WHERE Code = 'ALA'\G *************************** 1. row *************************** Code: ALA Name: Aland Islands Continent: Europe Region: Nordic Countries SurfaceArea: 13517.00 IndepYear: 1920 Population: 28700 LifeExpectancy: 82.5 GNP: 0.00 GNPOld: 0.00 LocalName: Landskapet Åland GovernmentForm: Parliamentary System HeadOfState: Sauli Väinämö Niinistö Capital: 4080 Code2: AX 1 row in set (0.00 sec)
削除を実施する。しかし、以下のようにエラーになった。
mysql> DELETE FROM country WHERE Code = 'ALA'; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`world`.`city`, CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`))
これは、「country
テーブルの削除しようとしているデータに紐付いている他のテーブルのデータがあるので、削除できない」というエラーだ。その他のテーブルは city
で、カラム名は CountryCode
とのことだそうだ。つまり、 city
テーブルにある CountryCode = 'ALA'
のデータがあるので、country
テーブルの Code = 'ALA'
のデータも削除できないのだ。先に city
テーブルのデータを削除する必要がある。削除する前に確認しよう。
mysql> SELECT * FROM city WHERE CountryCode = 'ALA'; +------+-----------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+-----------+-------------+----------+------------+ | 4080 | Mariehamn | ALA | Aland | 11186 | +------+-----------+-------------+----------+------------+ 1 row in set (0.00 sec)
確認してから、削除する。
mysql> DELETE FROM city WHERE CountryCode = 'ALA'; Query OK, 1 row affected (0.02 sec)
削除してから、また確認しよう。
mysql> SELECT * FROM city WHERE CountryCode = 'ALA'; Empty set (0.00 sec)
削除に成功したので、country からもデータを削除する。
mysql> DELETE FROM country WHERE Code = 'ALA'; Query OK, 1 row affected (0.02 sec)
削除してから、必ず確認する。
mysql> SELECT * FROM country WHERE Code = 'ALA'\G Empty set (0.00 sec)
今度は削除に成功した。
ここまでで、基本的な確認とデータ操作の説明を終わる。ここからは、データベースやテーブルの定義、変更などを簡単に説明する。
データベースの定義(CREATE DATABASE データベース名)
性質の異なる情報を同じ場所に保存しておくと、整理や取り出す時に混乱のもとになりがちだ。あれもこれも入れられる箱は入れる時には何も考えなくて良いので便利だが、いざ中身を見るときには中は大変なことになっているだろう。それを防ぐため、必要に応じてデータベースを分ける。
mysql> CREATE DATABASE `world2`; Query OK, 1 row affected (0.03 sec)
データベース定義文の確認(SHOW CREATE DATABASE データベース名)
一度作成したデータベースは、その作成時に使われたコマンドを再確認することができる。今作成した world2
データベースの定義文を見てみよう。
mysql> SHOW CREATE DATABASE world2; +----------+-----------------------------------------------------------------+ | Database | Create Database | +----------+-----------------------------------------------------------------+ | world2 | CREATE DATABASE `world2` /*!40100 DEFAULT CHARACTER SET utf8 */ | +----------+-----------------------------------------------------------------+ 1 row in set (0.00 sec)
/*!40100 DEFAULT CHARACTER SET utf8 */
の部分はデータベースで使用するデフォルトの文字コードの設定だが、文字コードについて説明し始めると長くなるのでここでは割愛する。
データベースの削除(DROP DATABASE データベース名)
定義済みのデータベースを削除することもできる。
mysql> DROP DATABASE world2; Query OK, 0 rows affected (0.09 sec)
あっけなく消えてしまう。バックアップを保存していない場合などは気軽に復元できないので気をつけること。
テーブルの定義(CREATE TABLE テーブル名...)
データベース同様に、テーブルも定義することができる。
mysql> CREATE TABLE test ( id serial, name text, created datetime default now() ); Query OK, 0 rows affected (0.05 sec) mysql> DESC test; +---------+---------------------+------+-----+-------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+---------------------+------+-----+-------------------+----------------+ | id | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | name | text | YES | | NULL | | | created | datetime | YES | | CURRENT_TIMESTAMP | | +---------+---------------------+------+-----+-------------------+----------------+ 3 rows in set (0.00 sec)
ここでは詳細は説明しない。カラムの種別などこまごまとした設定ができる。
テーブルの定義文を確認する(SHOW CREATE TABLE テーブル名)
こちらもデータベース同様に、一度定義されたテーブルは、その作成時に使われたコマンドを再確認することができる。
mysql> SHOW CREATE TABLE test; +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | test | CREATE TABLE `test` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` text, `created` datetime DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
テーブルの削除(DROP TABLE テーブル名)
定義済みのテーブルを削除することもできる。
mysql> DROP TABLE test; Query OK, 0 rows affected (0.01 sec)
こちらもあっけなく消えてしまう。バックアップを保存していない場合などはやはり気軽に復元できないので気をつけること。
テーブルにカラムを追加する(ALTER TABLE テーブル名 ADD COLUMN カラム名 カラム設定)
カラムを追加して、定義済みのテーブルの内容を変更することができる。
mysql> ALTER TABLE test ADD COLUMN modified datetime default null ON UPDATE CURRENT_TIMESTAMP AFTER created; Query OK, 0 rows affected (1.21 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc test; +----------+---------------------+------+-----+-------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +----------+---------------------+------+-----+-------------------+-----------------------------+ | id | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | name | text | YES | | NULL | | | created | datetime | YES | | CURRENT_TIMESTAMP | | | modified | datetime | YES | | NULL | on update CURRENT_TIMESTAMP | +----------+---------------------+------+-----+-------------------+-----------------------------+ 4 rows in set (0.00 sec)
テーブルからカラムを削除する(ALTER TABLE テーブル名 DROP COLUMN カラム名)
定義済みのテーブルからカラムを削除することができる。
mysql> ALTER TABLE test DROP COLUMN modified; Query OK, 0 rows affected (0.07 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc test; +---------+---------------------+------+-----+-------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+---------------------+------+-----+-------------------+----------------+ | id | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | name | text | YES | | NULL | | | created | datetime | YES | | CURRENT_TIMESTAMP | | +---------+---------------------+------+-----+-------------------+----------------+ 3 rows in set (0.00 sec)
コマンドを入力していて起こりがちなトラブル
最後に簡単に、よく起こりがちなトラブルについて触れておく。
コーテーションのとじ忘れ
以下のような表示になり、コマンドが終えられなくなってしまうことがある。
mysql> SELECT * FROM country WHERE Name ='Japan; '>
エンターキーを押し続けても、以下のように下に流れていくだけだ。
mysql> SELECT * FROM country WHERE Name ='Japan; '> '> '>
これは 'Japan
のように '
が不足しているから起きている現象で、次の '
を待っているので、コマンドが終わらなくなってしまっている。';
を入力してエンターキーを押すと、以下のように待ち状態を抜けられるので、改めて入力しよう。
mysql> SELECT * FROM country WHERE Name ='Japan; '> '> '> '; Empty set (0.01 sec)
他にあるあるなトラブルを思い出したら追加していく。
終わりに
なんだか随分長くなってしまった。書いてみて思ったが、やはりテーブルの結合が初学者のつまづきがちなポイントだと思う。とはいえ何度か使って慣れていけば、何も問題はないと思う。また、ここで説明した内容はデータベースサーバの持つ機能のうちのほんの一部でしかないし、説明を簡単にするために敢えて触れていないことや簡略化したことも多くある。データベースサーバには、大抵のやりたいことは叶えてくれるだけの機能が用意されているし、そのために内部はもっと複雑になっている。ぜひ、実際の動作やマニュアルをあたってみてほしい。
などと偉そうに書いてみたものの、調べてみると自分自身知らないことがたくさんあったので、それらについてここで説明しないまでも、とても勉強になったのでした。知識を自分なりにまとめるってすごく大切。
イタリア語版ミュータント・アンド・マスターマインドの舞台裏 〜エマヌエーレ・グラナテッロ、ミルコ・ペリチオーニ・インタビュー〜
執筆者:ルイージ "テンカー" カラファ (Luigi "Tencar" Carafa)
2018年2月1日 本家イタリア語版公開
2018年2月5日 非公式日本語版公開
まったくの偶然の出来事から記事が生まれることがあります。D&D(ダンジョンズ&ドラゴンズ)の優れたマスターであるエンリコ・カンティーレ(Enrico Cantile)とのチャットの中で、スーパーヒーローたちが活躍する宇宙を舞台にしたRPG、ミュータント・アンド・マスターマインド(Mutants & Masterminds)に出会ったこともまたそういった偶然の出来事です。
私はそれからイタリア語版RPGを制作担当したチームを探しはじめ、カイゾク・プレス社(Kaizoku Press)のエマヌエーレ・グラナテッロ(Emanuele Granatello)とミルコ・ペリチオーニ(Mirko Pellicioni)へのインタビューに成功しました。
ルイージ(筆者): ミュータント・アンド・マスターマインドをイタリアに持ち込むというアイデアは、いつどこで思い浮かんだのですか?
エマヌエーレ: 僕とミルコ・ペリチオーニとは何年も前からの知り合いで、僕たち(と、レリオ・ムーラス(Lelio Mulas)のことも忘れちゃいけないね)は、これまでに様々なプロジェクトに携わってきました(Fading Suns、Warcraft、ほかに実現はしませんでしたが Casal Pusterlengo 市郵便局の強盗)。僕は何年も前から、ウォーハンマーRPG第2版のテスト協力を通じてその編集者*1のことを知っていました。
僕たちは何か新しいものをもたらし、イタリアのRPG業界で勝鬨をあげたいと思っていました。それに僕たちはDCコミックスの『Legione』*2以来(ああ、Legione!懐かしい!)、本当に "インパクトのある" ものは見たことがなかった。そしてミュータント・アンド・マスターマインドは、これまた偶然にも、DCコミックスのゲームです(アメリカでは『DC アドベンチャーズ』という名前で出版されています)。
贔屓していると思われるかもしれませんが、それでも本当に、ミュータント・アンド・マスターマインドはスーパーヒーローのPRGだと思います。システムはすぐ覚えてすぐ遊べるようになっていて、信じられないぐらい柔軟です。おおむねD&Dと共通していますが、異なる点が2つあります。例えばより早いダメージの回復(バットマンシリーズの世界観でプレイしたい場合におあつらえ向き)、ポイントシステム(ゲームの柔軟性を、最近の他のゲームのレベルまで高めています)、複合システムはヒーローポイントのメカニズムにリンクしています(こういったジャンルの典型的なヒーローの行動とダークヒーローのジレンマとをすっきり解決し、いわゆる "ショッピングカート" のようにしてしまうことはありません)。
ヒーローパワーのシステム(本の中でも最も重要なルールです)についても、いわゆる "呪文のリスト" のようになることを避けるため、非常に簡潔にまとめられています。それにくわえて、キャラクターやアーキタイプのラピッドジェネレータ(高速生成システム)が用意されているので、プレイヤーは基本ルールブック(オールカラーで豊富なイラストつき)の中の、何十種類ものキャラクターやパワーをすぐに使用することができるようになっています。それから、主な設定を紹介するための二つのストーリー!ほかになにか必要ですか?もし足りないものが見つかったとしたら、僕は追加のエキスパンションを使います。ウェブサイトに用意されている基本ルールを直接ダウンロードしてみてください!
また、ミュータント・アンド・マスターマインドのマスタースクリーンや、PGやヴィランをより迅速に作成するために用意された、能力に関する分厚い(700ページ以上!)ルールブック、『パワープロフィール』(ゲームマスター向け、冒険やアドバイス、アイデア、いくつものサプライズが掲載されています。たとえば、魔法の章をご覧ください)も作りました。
ルイージ: 全体の翻訳をするのはどれぐらい難しいことですか?あなたがたにこの作品を委ねたのは誰ですか?
ミルコ: エマヌエーレとレリオの担当した翻訳作業には、かなり時間がかかりました。翻訳作業は、自分の言葉で文章をまとめるというだけでなく、通して読み、再読し、印刷してからさらに読み直し、第三者に読んでもらうことまでが含まれます(僕たちが変えなきゃと思っている作業もあります...時間がかかりすぎるからね!)。これが翻訳者の仕事です(模倣もありますが、これこそが本当の翻訳なのです)。グリーン・ローニンのスティーブ・ケンソン(Steve Kenson)とジョン・リーセウッサー(Jon Leitheusser)にも、ルールへの疑問や誤植の解消に関して、多大な助力をいただきました。グラフィックやレイアウトも尋常ではありませんでした。ミルコ・ペリチオーニ氏は最終段階での変更という、印刷上の大問題に直面しなければならなかった。それは銀河に打ち上げられた宇宙の侮辱であり、宇宙人の科学者たちは、将来ビッグバンの背景放射と一緒にこれについて研究することでしょう。
ルイージ: ルールブックのフォーマットはどのようにして決めましたか?
ミルコ: 単なるA4サイズではなく、本家同様にアメリカの用紙形式にすることを話し合って決めました。カバーについては、顧客に安く提供することを考え、最終的なコスト増につながるハードカバーでの装丁ではなくペーパーバックを採用しました。
エマヌエーレ: 当初僕は編み物のカバーを考えていましたが、ミルコは僕に、あまり独創的でないものを使うよう納得させました。僕たちは古風なソフトカバー装丁を、レギュラー版、そしてとても稀少なルッカ*3版(現在では手に入らず、タイプミスが目立ちます。Gronchi Rosa*4のような感じです)のふたつで採用しました(純粋なスーパーヒーロースタイルで)。ウールカバー付きの版なら冬のゲームプレイにも役立つし、きっと綺麗だったのに、残念です。(暖かさで世界は救われます。でも…Mr.Freeze にとってはダメでしょうけどね!)
ルイージ: あなたがたもRPGのプレイヤーですか?
ミルコ: 僕は1987年以来RPGを精力的に遊んできました。そもそもがRPGの大ファンで、それなしに今まで生きるのがまず無理でした。
エマヌエーレ: 間違いないですね。僕は1993年に(僕は同僚ほどのオタクではありません)、D&Dの赤箱*5からでした(正直に言うと、僕より先にRPGで遊んでた人たちは、ヒーロークエストをやっていました)。僕の一番のお気に入りは、いまだにウォーハンマーRPG(初版と第二版)です。でも、他にもすごく雑食に遊んできました。
僕はスター・ウォーズRPGも好きだし、クトゥルフの呼び声、Rifts(ああ、Rifts…サイバー女とロータリー、喜びと悲しみ)、ミュータント・クロニクルズ、Fading Suns、パラノイア…などなど。もちろん、様々な派生版やたくさんのD20で、AD&D(アドバンスト・ダンジョンズ&ドラゴンズ)も遊んできました。ミュータント・アンド・マスターマインド(とTrue20、その後継)は、システムの到達点だと僕は思います。僕にはスティーブ・ケンソン(Steve Kenson)*6がどうやってそれに成功したのかはわかりませんが、70年代にもたらされた残滓*7は、柔軟かつシネマチックな珠玉作を産み出しました(ヒットポイントとレベルなしで!)。
ミルコ: すべては、1987年に僕が最初にローンウルフのゲームブック、それからThe Dark Eye*8と出会い、RPGがいったいどういうものなのかまったく知らないままに購入したときから始まりました。幸いなことに、僕の住んでいたボローニャには僕のような愛好家の集まるグループ(“Circolo degli Scacchi”や“Ludoteca giocano i Grandi di Corticella”)がたくさんありました。もちろん、僕にとっての二番目のRPGはD&Dで、それからルーンクエスト、クトゥルフの呼び声、そのほかにもたくさんあります。僕は古くからの愛好家のひとりですが、過去15年間の新しい革新的なゲームのことも大好きです。
エマヌエーレ: 子供の頃から、女の子に人気がなく、何事にもうんざりしていて、その名に相応しいコンピューターやコンソールも持ち合わせていない、基本的にオタクになろうとしていた僕(彼らにまだのど仏が無かったころ、永遠の天使たち!)には2つの選択肢しかありませんでした。シリアルキラーになるか、はたまたRPGか。僕はその両方の活動に専念していて、はっきりとどちらかを選んだわけではありませんでした。僕はカゼルタにある僕の大きな家で、長いRPGセッションを開催しましたが、それが終わる頃には、プレイヤーもキャラクターも消えてしまいました(必ずしもこの順序ではありません)。事態が悪化しはじめた時、僕は今住んでいる日本へと移りました。RPGを遊ぶことは少なくなりましたが、翻訳することは増えました。
ルイージ: 紙のマニュアルの出版を補助する目的で、タブレットやその他のサポートが可能なPDF形式やその他形式で配布するというアイデアについては考えましたか?
エマヌエーレ: はい。僕たちカイゾク・プレス社としてはそれについて考慮していて、2018年にはニュースをお知らせできます。僕は、僕たちが転換点にいると確信し続けています。紙はデジタルに道を譲りました。その道はまもなくウールに譲られることでしょう。ウールこそが未来です。その間に、僕たちはすでにデジタル配信を開始しており、僕たちのオンラインショップ(http://mutantsandmasterminds.it/ および http://kaizokupress.it/)では、紙でも購入することができます。Drivethrurpg*9 でも購入できます。さらに、Terra dei Giochi(僕たちと提携している数少ないショップのうちのひとつ)では、Webサイト terradeigiochi.it 上で、ミュータント・アンド・マスターマインドのために作られた数多くの素材(公式・非公式ともに)を取り扱っています。また、昨年12月にはイタリアで作られた最初のアドベンチャーが出版されました(無料)。なんとあのLegion (ああ、Legione!懐かしい!)の著者、ダニーロ・モレッティ(Danilo Moretti)によって書かれました。
ルイージ: これからの計画はありますか?すでに作業場に置かれている仕事はありますか?
ミルコ: たくさんのプロジェクト、アイデアだけでなく、他のチームとのコラボレーションや共同制作もあります。カイゾク・プレス社として、現時点では、ジョン・コヴァリック(John Kovalic)によって描かれた『子供たちを食べるコボルドたち』という、ビールとポテトチップから生まれた最初のRPGが作業場に置かれています!その後には、もっと古典的なほうへ移って、M&Mとメガ・アドベンチャーのための一組のエキスパンションと、すでにアメリカで販売されているD&D第5版のためのダンジョン・エポック『Rappan Athuk』の翻訳を行います。端的に言えば、僕たちの名前を信じてください(『Kaizoku』は日本語で『海賊』を意味します)。僕たちは新しい手法の出版で、みなさんを驚かせます(とにかく買って買って、買ってください!できれば、僕たちのサイトで)。
ルイージ: あなたがたのこれからの意欲に感謝を!
出典: https://nerdando.com/2018/02/01/ce-dietro-ledizione-italiana-mutants-masterminds/
*1:クリス・プラマス(Chris Pramas)、グリーン・ローニン(Green Ronin)の代表。RPG以外に食べ物、ウォーゲーム、パンク音楽、ドナルド・トランプとその支持者をからかうことの4つに情熱を燃やしている
*2:訳注: 1990年に発売されたアメコミ
*3:ルッカゲームズ。イタリア最大のアニメ・ゲーム・漫画イベント。年一回ルッカ市で開催される。
*4:イタリアの切手。描かれていたペルーとエクアドル間の国境に誤りがあり、訂正版が印刷された。
*5:ダンジョンズ&ドラゴンズ・スターターキットのこと
*6:ミュータント・アンド・マスターマインド、True20 などのゲームデザイナー。
*7:訳注: 1974年に誕生したダンジョンズ&ドラゴンズのこと。
*9:訳注: RPG関連のWeb通販サイト。http://www.drivethrurpg.com/。
2017年を振り返る
この年齢にもなって恥ずかしながら、自分はとても懐疑的な人間で、それが奏功する場面もあるにはあるのですが、もちろんいつもうまくいくわけではありません。
物事を教わるにしてもそうで、「これこれこういうことが起こらないように、こうするのです」と聞いても、その場では「本当にそうか?それが起きないこともあるのではないか?」と考えがちで、いったん先入観でそうなってしまうと素直に受け入れることができません。
またそういう場合は実感もわきにくく、「そういうこともあるんだろうな」と思おうとしても実際の場面がなかなか想像できないので、いざ直面してみるまでは不測の事態が予期できず、無意識のままに、もしくは楽天的に捉えて、「こうするのです」の部分を破ってしまうことがあります。そしてそのとき初めて「なるほどこういうことが起きないように、こうするのか」と、実感とともに合点がいくのです。
2017年は、とくにそういう年でした。
面白かった本について
小説
『あなたの人生の物語』著:テッド・チャン
- 作者: テッド・チャン,公手成幸,浅倉久志,古沢嘉通,嶋田洋一
- 出版社/メーカー: 早川書房
- 発売日: 2003/09/30
- メディア: 文庫
- 購入: 40人 クリック: 509回
- この商品を含むブログ (392件) を見る
映画『メッセージ』の原作を含む短編集。映画を見てからでも良いので、原作も読むべきだなと思いました。原作ではすこし想像しづらい描写が映像になっていますし、逆に映画での描写の意味が原作での心理描写にあらわれています。より深く楽しめることでしょう。
新書
『日本語 <上・下>』著:金田一春彦
今年は仕事の関係で校正の作業をすることになったので、知識の裏付けの意味もあって日本語関係の書籍をたくさん読みました。そのうちのひとつです。
校正では人の文章に対して少なからぬ提案や指摘をするのですが、その際に「なんか読みにくいから変えてください」とは言えません。多くの場合、説得力のある理由を添える必要があります。この本はその助けになりました。
漫画
とめはねっ!鈴里高校書道部 14 (ヤングサンデーコミックス)
- 作者: 河合克敏
- 出版社/メーカー: 小学館
- 発売日: 2015/05/29
- メディア: コミック
- この商品を含むブログ (20件) を見る
『帯をギュッとね!』や『モンキーターン』を描いた作者による、書道漫画です。テレビドラマにもなりました。1巻から9巻までは去年までに読んでいて、一昨年14巻で完結したことも知っていたのですが、今年になってやっと読み終えました。
近年まれに見る、とても綺麗にまとまった終わり方をした漫画だなと思いました。非現実的なほどに大人びた高校生や、バカで無責任すぎる大人も登場しないし、作者が言いたいことを言うためだけのキャラクターも出てこない。作者が透けて見えないことに、一番好感を持てました。
お酒について
「楽しいお酒を飲む」が今年の目標でした。来年もそのままかなと思います。
年々、飲むと沈むことが増えてきたような気がします。その場は楽しいんですけど。
確定申告について
やりましたが、8ヶ月も前のことでもはや忘れました。最初は freee や MonerForward などのサービスを使ってみましたが、最終的には税務署のWebサイトにあるサービスを使うのが一番楽だったように思います。
そういえば、サービサーとして世の中に何を提供すべきなのかについて考える年でもありました。
よくラーメン屋のたとえ話をしているのですが、世の中にあるものの品質が徐々に下がり、言わば「フードコートのラーメン屋」になっているような気がするのです。それも、看板だけは「老舗の名店」のままで。
するとどうなるかと言うと、少しずつそれが「老舗の出すうまいラーメンの味」として認識されていくのです。もちろん食べた人全員がそう思うわけではないでしょう。しかし味がわかる人だけでないこともまた事実です。
あくまで例え話ですが、ここで言う「老舗の名店」のオーナーが、ラーメンの味がわからないこともまたあります。そんなオーナーが、他の料理人から安価でうまいラーメンを作れると聞けば、今まで雇っていた料理人を入れ替えることでしょう。そしてその安価なラーメンの実態がフードコートのラーメンだとしても、オーナーにはわかりません。
さらに悪いことに、オーナーの店は人通りのある表通りにあり、かつ店の壁に貼られた広告による収入が、ラーメンの販売で得られるそれよりも上回っているのです。多少味のわかる人に幻滅されたとしても、他にも人はたくさんいますし、そもそも人さえ来てくれれば、ラーメンが売れる必要はないのです。
それはもはやラーメン屋なのでしょうか。
そしてそのよくわからない何かは、いったい誰に価値を提供しているのでしょうか。
というようなことを考えたり、悩んだりする年でした。安価で一流のラーメンを作る方法さえあれば、この流れに乗って世の中が良くなっていくと思うのですが、答えは出ていません。
2018年の目標
イタリア語
イタリア旅行を機に今年の8月から勉強しているイタリア語ですが、当然ながらまだまだ身についていませんし、来年も続けます。
今はフレーズ本や単語集を読んだり、勤務中に書籍に付属のCDを聞いたり、Facebook にイタリア語で書き込んだり、NHKの教育番組を見たりしています。来年は、それらに加えて新たにディクテーションをやってみようと思います。
来年の終わりまでには、せめて意味のわかる文を書いたり、多少詰まってでも言いたいことが言えるようになったりしたいなあ。背伸びして翻訳もやってみたい。それにもう一度イタリアにも行きたいなあ。
それではみなさま良いお年を。
イタリア旅行 - 言葉編
イタリア旅行で感じた、言葉についてのことを書きます。
あくまで自分が感じたことにすぎないので、誤りもあると思います。鵜呑みにせず、一意見としてご参考ください。
通じる言語
イタリアの公用語はイタリア語*1です。国家形成の経緯の影響で特徴的な方言が各地方に多くありますが、基本的に全域で共通イタリア語が通じるようです。
そのほか北部でフランスと近い地方ではフランス語が、ドイツと近い地方ではドイツ語が、スイスと近い地方ではスイス語が通じるという話もありますが、自分にはわかりませんでした。
英語は、観光地では基本的に通じますが、日本よりもやや多くの人が話せるかなぐらいの感覚で、挨拶やYes/No、数字、簡単な説明ぐらいであればほぼ全員が話せていたように感じました。少なくとも、ホテルのスタッフや店員さんは全員英語が話せると思って間違いないと思います(バスの運転手さんは怪しいけど)。
とはいえ日本で外国人が「コンニチハ」と言ってくれるとなぜか嬉しいのと同様に、イタリアで「Buongiorno」と挨拶すると嬉しそうにしてくれる人もいます。イタリア語も覚えていったほうが、イタリア人とのコミュニケーションは捗ることでしょう。
最低限覚えたい単語・フレーズ
おそらくどんな言語でもそうですが、以下は最低限覚えて行ったほうが良いと思います。
- ありがとう
- はい
- いいえ
- すみません(呼びかけ)
- ごめんなさい
- おはようございます
- こんにちは
- こんばんは
- またいつか会いましょう
- 美味しい
- トイレはどこですか?
- 1〜20 までの数字
イタリアの場合、「トイレはどこですか?」は非常に重要です。トイレの切れ目が旅の切れ目です。いつでも場所を確認できるようにしておきましょう。上記それぞれのイタリア語は以下です。
- Grazie(グラッツェ) ありがとう
- Sì(スィ) はい
- No(ノ) いいえ
- Scusi(スクズィ) すみません(呼びかけ)
- Mi scusi(ミスクズィ) ごめんなさい
- Buongiorno(ブォンジョルノ) おはようございます
- Buongiorno(同じ) こんにちは
- Buonasera(ブォナセーラ) こんばんは ※15時ぐらいから使う
- Arrivederci(アッリヴェデルチ) またいつか会いましょう ※「さようなら」は Addio(アッディーオ)
- Buono(ブォノ) 美味しい
- Dov'è il bagno?(ドヴェ イルバーニョ?) トイレはどこですか?
1〜20 までの数字は、
- Uno(ウノ) ※同名のカードゲームがありますね
- Due(ドゥーエ)
- Tre(トレ)
- Quattro(クアットロ) ※ピザのクアトロフォルマッジは「4つのチーズ」です
- Cinque(チンクエ)
- Sei(セイ)
- Sette(セッテ)
- Otto(オット)
- Nove(ノヴェ)
- Dieci(ディエチ)
- Undici(ウンディチ) ※Uno + Dieci
- Dodici(ドーディチ) ※Due + Dieci
- Tredici(トレーディチ) ※Tre + Dieci
- Quattordici(クァットールディチ) ※Quattro + Dieci
- Quindici(クィンディチ) ※Cinque + Dieci
- Sedici(セーディチ) ※Sei + Dieci
- Diciassette(ディチャッセッテ) ※Dieci + Sette
- Diciotto(ディチオット) ※Dieci + Otto
- Diciannove(ディチャンノーヴェ) ※Dieci + Nove
- Venti(ヴェンティ)
このあたりは値段でよく聞きました。あとは10刻みで30,40,50...と覚えておいたほうが良いですが、それがなくてもおそらくなんとかなります。
よく使ったフレーズ
最低限覚えておけば良い言葉があれば大丈夫だと思いますが、それ以外にイタリア旅行中よく使ったフレーズを紹介していきます。
クレカ使えますか?
Posso pagare con la carta di credito? (ポッソ パガーレコン ラカルタディクレディト?)
レストランや個人商店、ホテルなどで非常によく使いました。返事は以下のような感じです。
- Certo.(チェルト) =もちろん
- Sì.(スィ) =はい
- No, non accettiamo.(ノー ノナッチェティアーモ) =いいえ、受付できません
これください
Prendo questo.(プレンド クェスト) ※ひとつだけの場合
Prendo questi.(プレンド クェスティ) ※複数の場合
Prendo questa e... questa.(プレンド クェスタ エー… クェスタ) ※「これと〜…これください」と、ショーケースを見ながら考える感じ
黙ってショーケースを指差したり、黙ってレジに持っていっても「買いたい」という意思は伝わりますが、気持ち良い買い物のため、何か一言言いたいものです。そんなときに、自分はこう言いながら買い物していました。ピザ(pizza)などは女性名詞なので、それを指し示すための「これ」も女性名詞形の questa にしてやる必要があったり、厳密に考え始めるとすこしややこしいですが、すべて questo で押し通しても観光客オーラでなんとかなると思います(もちろんきちんと学習したい人はそうはいきませんが)。
ふたりです
Siamo in due.(シアモ イン ドゥーエ)
日常的にレストランやピザ屋に入った際、何人か聞かれるのでこう答えていました。たいてい「ここに座れ」とか「好きな所へどうぞ」とか、手振りと言葉で示してくれます。
予約してます
Ho una prenotazione.(オウナ プレノタツィオーネ) ※イタリア語では「H」は発音しません。
主にホテルのチェックイン時によく使いました。こう言ってから予約票を見せると、スムーズに受付が済みます。しかし同時に、その後の朝食やクリーニングなどの説明もすべてイタリア語で話されてしまうという諸刃の剣でもあります。自信がなければ英語か手振りでいきましょう。
これいくらですか?
Quanto costa?(クアントコスタ?)
たいていのものには値札がついていますが、ときたま値札もシールもついていないことがありました。そんなときにはこのフレーズ。返事は以下のような感じです。
- Dodici.(ドーディチ) =12(ユーロ)
- Venti euro.(ヴェンティエウロ) =20ユーロ
- Dieci e trenta.(ディエチエトレンタ) =10ユーロ30セント
お会計お願いします
Il conto, per favore.(イルコント ペルファヴォーレ)
レストランに入って、座って、メニューを見ながら注文して、食べて…という一連の流れは何も言わなくても済みますが、店を出るときだけは「会計して出たい」という意思を伝える必要があります。そんなときのフレーズがこれ。
ちなみにイタリアではテーブル会計が多かったように思いました。レシートが置かれていない場合でも、店員さんを呼んで上のフレーズを言えば、内訳を記載したレシートを持ってきてくれます。とはいえカウンター払いやレジ払いの店もあるので、周囲を観察するなどしてその店のやり方を見習いましょう。
どれも美味しかったです
Era tutto buono.(エラ トゥット ブォーノ)
レストランのお会計時に言うと受けが大変良いです。美味しかったならぜひ言いましょう。
楽しかったです
È stato un piacere.(エスタート ウンピアチェーレ)
ホテルのスタッフや、路上で絵を描いている人、本屋の店員さんなど、イタリアではたくさんの出会いがあり、その都度会話があります。もし楽しかったなら、別れ際にぜひこう言いましょう。
大人二枚お願いします
Due interi, per favore.(ドゥーエ インテリ ペルファヴォーレ)
美術館や博物館でチケットを買う際によく使いました。intero は「完全な」とかいう意味ですが、子供料金半額などに対し、全額払うという意味なのだと思います。
ここは私の席だと思います
Credo che questo è il mio posto.(クレドケ クェストエ イルミオポースト)
別記事にも書きましたが、長距離列車であるフレッチェは、全席指定席にも関わらず、すでに人が座っていることがしばしばあります(5回中2回ありました)。その際に自分の権利を主張するための言葉がこれです。車両番号に自信がないなど、Credo (クレド 信じる)とまではいかないのであれば、Penso (ペンソ 思う)で言い換えましょう。
持ち帰ります(テイクアウトします)/店内で食べます
Portò via.(ポルトヴィア) =持ち帰ります
Mangio qui.(マンジョクイ) =ここで食べます
信じられないかもしれませんが、意外とマクドに行きます。その際「Mangia qui?(マンジャクイ?)=ここで食べますか?」と聞かれるので、こう答えましょう。
ちなみにイタリアのマクドナルドには、店内にタッチパネル式の自動注文機がある場合があります。ここで注文を済ませ、レシートを受け取ると、品物受け渡し口でレシート記載の番号が呼ばれるという仕組みです。口頭で注文しなくて済むので便利ですが、テイクアウトか店内かの選択だけは、口頭ですることもあります。
この添付ファイルを印刷してもらえますか?
Può stampare questi allegati?(プオ スタンパーレ クェスティアッレガティ?)
イタリア旅行前にすべての予約を済ませ、家で印刷物をプリントアウトしてから出発していれば不要なフレーズですが、急にどこどこの博物館を予約しただとか、帰りの飛行機のWebチェックインをしただとかで、メールで送られてきた予約票や航空券を印刷したくなることがあります。
たいていのホテルは受付で印刷を引き受けてくれるので、このフレーズでメールを見せながら頼んでみましょう。自分は3回ほど経験しましたが、すべて、まずメールをホテルのアドレス宛に転送し、それを印刷してもらう、という流れでした。ホテルによっては1枚1ユーロなどと有料なこともあるので、確認が必要です。
切符(チケット)はどこで買えますか?
Dove posso complare i biglietti?(ドヴェポッソ コンプラーレ イビリエッティ?)
観光地化された教会などに入りたいのに、どこでチケットを買えばいいのかわからないとき、その場で警備している警察官や軍人さんにこう聞いてみましょう。まずどんな人でも指差してくれますし、「Là(ラー)=あそこ」「LÌ(リー)=あそこ」「Sinistra(シニストゥラ)=左」「Destra(デストゥラ)=右」などが聞き取れれば安心です。
荷物を預かってもらえませんか?
Posso lasciare qui i miei bagagli.(ポッソラシャーレクイ イミエイバガーリ)
ホテルのチェックアウトから列車の発車までに時間がある場合、荷物を置いてまだすこし観光したいですよね。そんなときはこう言って確認してみましょう。自分の場合は「ロビーに置いておいて」と言われることがしばしばでした。
ひとつ聞いてもいいですか?
Posso avere un'informazione?(ポッソアヴェーレ ウニンフォルマツィオーネ?)
何か質問したいとき、非常によく使いました。イタリア人の友達が「Un'informazione?」の部分だけで使っていたので真似してそこだけ言っていたんですが、それでも普通に通じたので、後半だけでもいいのかもしれません(少なくとも、変なやつだとか無礼なやつだとか思われているような表情はされませんでした)。
Posso chiederLe una cosa?(ポッソキエデルレ ウナコーザ?)
同じような意味で、こう言うこともできるようです。自分は結局「Un'informazione?」で乗り切ったので、使いませんでした。
手に取っていいですか?
Posso prendere in mano?(ポッソプレンデレ インマーノ?)
お店で陳列されているもので、いかにも壊れそうなものだったり、そもそも触っていいのかどうか迷ったときに、確認のため使いました。
あー良かった。
Meno male.(メノマーレ)
「何か悪いことになりそうだったけど、そうならなかった」というニュアンスの「あー良かった」です。意外に使いますし、これが言えるとイタリア人からニヤッとされます。
これ好きです。
Mi piace questo.(ミピアーチェ クェスト)
例えば料理や絵画など、何かが気に入ったときに積極的に使いました。買い物のときに好みを伝えると、「これが好きなら、これはどう?」とおすすめしてもらえるので助かります。
本当に?
Davvero?(ダヴェーロ?)
相手が言ったことに対するリアクションとしてよく使いました。「Dici davvero?(ディチ ダヴェーロ?)=本気で言ってるの?」などもよく使います。
わかりました。
Ho capito.(オカピート)
相手の説明がわかったら言いましょう。相槌で「なるほど」と言いたいときには、「Capisco.(カピスコ)=なるほど」と言うようにしていました。
(お金を払いながら)これどうぞ
Ecco a lei.(エッコ アレイ)
単に物を渡すときには「Prego.(プレゴ)=どうぞ」が便利ですが、お金を払うときだけは自分はこう言っていました。正しいのかは謎ですが、とくに変な顔もされませんでした。
なぜイタリア語を話すべきか
冒頭で書いた通り、イタリアでは英語が割と通じます。しかしながら、自分はイタリア語を覚えてイタリアに行き、実際に話してみて、できるだけイタリア語で話したほうが良いなと感じました。
それは相手が嬉しそうにしてくれるということもありますが、それ以上に、親しくしてくれるようになるからです。中には、少しだけでも話せることがわかると、こちらが聞き取れるようにゆっくりと、難しい単語を使わず話してくれる人もいます。逆に日本語の簡単な単語を覚えようとする人もいます。こちらが「Buono!」と言うと、誰が教えたのか、「オイシイ!」と笑顔で返してくれる店員さんもいます。そんな人たちとイタリア語を使ってコミュニケーションすることは、きっと感動を伴った忘れられない思い出になるでしょう(自分はなりました)。
少しの努力だけで、旅行がより良い、思い出深いものになるのですから、やはり現地語を覚えて出発するほうが良いと思います。
それに、旅行先で外国語で話すことは、「次はもっと上手くなる!」というモチベーションを高めるためのきっかけをくれます。たいてい、最初はなんでも上手く言えません。自分の場合も、知らない物の名前や知らない用法に直面し、結局は手振りや、まだイタリア語よりは使える英語に頼ってしまうことがしばしばありました。また、ネイティブのイタリア語は全然聞き取れません。これまた「次は完璧に聞き取ってやる」というモチベーションにつながります。たくさん失敗することが、帰国後に学習を継続するための力になるのです。
もちろん「下手なイタリア語で話しおって」とか「最初から英語で言え」とか思われている可能性も大いにあります。とくに自分の仕事をさっさと終わらせたい人が相手だと、その傾向が強いでしょう。しかし、だからといって遠慮していてはいけません。相手はイタリア人ですし、自分が話そうとしているのもイタリア語です。彼らの真似をしてイタリア人らしく己の主義を貫くことに、何の遠慮が要りましょうか。
また、自分は「発音が上手い」としばしば言われました。これは完全にはお世辞ではないようで(部分的にはそうかもですが…)、書籍を当たると「日本人はイタリア語の発音で有利」という記載によく出会います。実際、英語圏出身者のイタリア語で、「cucinare(クチナーレ)=料理する」を「クシナーレ」と発音している人に出会い、聞き取るのに苦労しました。もしかしたらそれは方言だったのかもしれませんが、いっそ「自分のほうがより正しい共通イタリア語の発音をしっかりできてるんだ」と自信を持って発言してしまいましょう。
どう勉強したか
「勉強」というと堅苦しいですが、自分の場合は書籍と、イタリア人の友達に質問するという二つの方法で、旅行前に3ヶ月かけて、少しだけイタリア語を習得しました。
書籍
本屋さんでイタリアのガイドブックと一緒に購入しました。基本の113フレーズと、各フレーズの派生フレーズが収録されていて、音楽にのせて日本語とイタリア語を音読した CD も付属します。
自分の場合は「まずとにかく口で覚えること」を意識して、CDを聞きながら自分でも口ずさみ、覚えにくいものは筆記しながら口に出してみたり、そのフレーズを言いそうな気持ちになって言ってみたり、いろいろやってみました。
仕事中もなるべくCDを聞き、1日1時間は最低限勉強できるようにしました。そのおかげか、3ヶ月の間で、基本フレーズ113のうちの80%ぐらいはスムーズに言えるようになったと思います。
中には「これいつ使うねん」と思うようなフレーズ(「父のためにネクタイを探しています」とか)も入っていますが、そのフレーズに含まれている単語(この場合は「探す」など)が意外に重要だったりと、覚えて損はしない構成かなと思いました。
また、不定冠詞・定冠詞や、数字、曜日、月、代名詞なども掲載されていて、その一覧をそのまま、覚えるまで書き写すことで頭に入れました(だいたい5回目ぐらいで覚えられます)。
デイリー日伊英3か国語会話辞典 カジュアル版
こちらは勉強には使用していません。旅行直前に購入し、イタリアでとても役に立ちました。
27のシーン別にフレーズが合計1,200収録されていて、たいていの言いたいことはこれを見れば言えました。といっても相手の前で堂々と引くというよりは、予め引いて覚えてから言う、という使い方です。
小さめのサイズなので肩掛けバッグの中にも入りますし、いざというときのための保険として忍ばせておくと安心できます。
旅行前に読んだ書籍は、ほとんど上の2冊だけです。もちろんこれだけでは文法や語彙は身につかないので、帰国後に買い足しました。
以上、イタリア語についてでした。思い出し次第追記していきます。