【mariaDB】コマンドチートシート

2020/06/01 01:26 その他::技術情報

前提条件

DB 名 / テーブル名 / フィールド名 / エイリアスの例示

DB 名
3文字に続いてデータベースを示す。
***_database
***_db
xxx_db
yyy_db
テーブル名
3文字に続いてテーブルを示す。
***_table
***_tbl
xxx_table
yyy_table
フィールド名の例示
3文字に続いてフィールドを示す。
***_field
***_fld
***_column
***_clm
xxx_field
yyy_field
エイリアスの例示
きちんと表示させた場合はバッククォート ` で括る必要があるが、省略。
select * from xxx_tbl as x order by `x`.xxx_fld;

select * from xxx_tbl as x order by x.xxx_fld;

大文字 / 小文字

mariaDB では SQL に大文字/小文字の指定はないみたい。
> SELECT * FROM ***_table;
> Select * From ***_table;
> select * from ***_table;
サンプルは小文字で書いている。
たぶん、業務で使うなら SQL 部分を見やすくするために大文字で統一すると思う。

改行

SQL の末尾(SQL の実行)を示すために ; を記述するようで、コマンド以外ならどこで改行を入れても問題なさそう。

短いなら1行で書いてもいいけど、条件等が長くなるようなら段落を使って構造を把握しやすくする。
> select
    *
  from
    xxx_table
  where
    xxx_field = "0"
  ;

CREATE

テーブルを作成する。

通常

基本形
> create table xxx_table ( aaa_field int unsigned not null auto_increment primary key);
いろいろ作りたいとき。
> create table xxx_table (
    aaa_field
      int unsigned
      not null
      auto_increment
      primary key,
    bbb_field
      int,
    ccc_field
      varchar(255),
    ddd_field
      tinyint unsigned
      not null,
    eee_field
      datetime
      default current_timestamp,
    fff_field
      datetime on current_timestamp
      default current_timestamp,
    ggg_field
      bit(1)
  );

SELECT

通常

select を利用した SQL の基本形
> select * from xxx_table;

内部連結 (inner join)

内部連結 inner join は、指定したフィールドの値が一致するデータ(連結先で Null 等がある等)しか取得できない。

どちらかのテーブルにしかないデータが不要な場合に使う。
テーブル二つを連結
> select * from xxx_table as x
    inner join yyy_table as y
      on x.zzz_id = y.zzz_id;
テーブル三つを連結
> select
    *
  from
    xxx_table as x
  inner join yyy_table as y
    on x.yyy_id = y.yyy_id
  inner join zzz_table as z
    on x.zzz_id = z.zzz_id;

外部連結 (outer join)

外部連結 outer join は、指定したフィールドの値が一致するデータ(連結先で Null 等がある等)も取得できる。

どちらかのテーブルにしかないデータを取得したい場合に使う。
左側基準 (left outerjoin)
join の左側データを基準に連結。
join された側のテーブルにしかないものは取得しない。
> select x.fld, y.fld from xxx_table as x
    left outer join yyy_table as y
      on x.zzz_id = y.yyy_id;
右側基準 (right outerjoin)
join の右側データを基準に連結。
join 前のテーブルにしかないものは取得しない。
> select x.fld, y.fld from xxx_table as x
    right outer join yyy_table as y
      on x.zzz_id = y.yyy_id;
基準なし (full outerjoin)
どちらのテーブルにも、それぞれでしか存在しないものでも取得する。
> select x.fld, y.fld from xxx_table as x
    full outer join yyy_table as y
      on x.zzz_id = y.yyy_id;

条件指定 (where)

> select *
  from xxx_table
  where yyy_id = 2;
> select *
  from xxx_table
  where
    yyy_id = 2
      or
    yyy_id = 3
;

並べ替え (order by)

昇順 (asc)
1個
昇順の指定 (asc) は省略
> select
    *
  from
    ***_table
  order by ***_field
  ;
複数
昇順の指定 (asc) は省略
> select
    *
  from
    xxx_table
  order by
    xxx_field,
    yyy_field
  ;
降順 (desc)
降順の指定は (desc)
> select
    *
  from
    ***_table
  order by ***_field desc
  ;
文字を対象 (asc)
UTF-8 を対象に
> select
    *
  from
    ***_table
  order by
    ***_field
      collate
        utf8_unicode_ci
  ;
使ったことない
> select
    *
  from
    ***_table
  order by cast(***_field as char)
  ;

INSERT

フィールド全部を対象に入れるとき

> insert
    into xxx_table
  values (
    default,
    "column",
    null
  );

フィールド個別に入れるとき

> insert
    into xxx_table (
      xxx_field,
      yyy_field
      )
  values (
    default,
    "column",
    null
  );

UPDATE

列単位でアップデート

field1 の列を全部 value1 にしたいとき
update ***_table
  set field1 = value1;

指定の行だけアップデート

field2 が value2 である field1 列の特定行を value1 にしたいとき
update ***_table
  set
    field1 = value1
  where
    field2 = value2;

フィールドコピー

xxx_fld の列を全部 yyy_fld に合わせたいとき
update ***_table
  set xxx_fld = yyy_fld ;

DELETE

指定行を削除
> delete from ***_table
where xxx_field = 1;
テーブル内全削除(TRUNCATEを使うべき)
> delete from ***_table;
降順で3つの行を削除
> delete from ***_table
order by xxx_field desc limit 3;

DROP

drop の対象は、DBそのものと、DB内のテーブル。

データベースをドロップ

> drop database ***_db;

テーブルをドロップ

> use ***_db;
> drop table ***_table;

その他

TRUNCATE

指定テーブル内の全データを削除し、auto_increment も初期化する。
> truncate table ***_table;

SHOW

show は、mariaDB そのものを参照したい場合に利用する。
DATABASES
> show databases;
TABLES
> show tables;

DESCRIBE
> desc ***_table;

ALTER

テーブル自体に操作を加えたいときに ALTER を利用する。
デフォルト値の変更
varchar(x) の場合
> alter table xxx_table
    alter xxx_field
      set default "aaaa";
bit(1) boolean の場合
> alter table xxx_table
    alter xxx_enable
      set default true;
フィールドの追加
最初に追加
> alter table ***_table add ***_field integer first;
符号なし unsigned の場合の指定
> alter table ***_table add ***_field integer unsigned first;
テーブルにデータが追加されたときだけ、タイムスタンプが自動更新されるフィールドの追加
> alter table ***_table
  add ***_field datetime default CURRENT_TIMESTAMP
  first;
テーブルの、他のフィールドが更新されたときもタイムスタンプが自動更新されるフィールドの追加
> alter table ***_table
  add ***_field datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  first;
末尾に追加
> alter table ***_table add ***_field integer;
複数の場合
> alter table ***_table add (xxx_field integer, yyy_field varchar(5));
指定フィールドの次に追加
> alter table ***_table add yyy_field integer after xxx_field;
フィールドの削除
> alter table ***_table drop column ***_field;
フィールドの型を変更
> alter table ***_table modify ***_field integer;
Default のあるカラムを Not Null にしたいとき
> alter table ***_table modify ***_field DateTime Not null Default CURRENT_TIMESTAMP;
符号なし int 等いろいろ付与したい場合
> alter table ***_table modify ***_field integer unsigned Not null auto_increment;
Primary key がないので付与したい場合
> alter table ***_table modify ***_field integer unsigned Not null primary key auto_increment;
フィールド名の変更
変更後のフィールド名は、型の宣言が必要。
> alter table xxx_table change xxx_field yyy_field varchar(1000);
auto_increment の番号設定(初期化)
> alter table xxx_table auto_increment = 1;

IPv4アドレスのソート方法あれこれ

2021/05/21 05:34 その他::技術情報

IPv4アドレスのソート方法あれこれ
IPv4 のリストは、ソートしたくなる時があります。
いろいろな場面で使えるソート方法を書いてみました。

とは言ってもいまのところ、そのままで IPv4 形式を扱えるコマンドオプションを利用するか、ロングIPアドレスの形式に直して扱うかの2択なんですが。

Linux 編

Bash (シンプルなIPアドレスソート)

ソート対象のサンプルファイルが、これです。

sample.txt
1.2.3.4
1.1.1.1
20.10.5.3
3.5.7.9
7.10.5.4
60.70.80.90
9.8.7.6
150.150.150.150
7.6.5.4
ソートしたい対象が、シンプルに IP アドレスだけなら簡単。 bash ならね。

sort コマンドに --version-sort オプションがあります。
(ほら、バージョン情報もドットで区切る数値の塊だから)
$ sort --version-sort sample.txt
1.1.1.1
1.2.3.4
3.5.7.9
7.6.5.4
7.10.5.4
9.8.7.6
20.10.5.3
60.70.80.90
150.150.150.150
こちらは、まったく同じオプション(省略形)です。
$ sort -V sample.txt
1.1.1.1
1.2.3.4
3.5.7.9
7.6.5.4
7.10.5.4
9.8.7.6
20.10.5.3
60.70.80.90
150.150.150.150
bash バージョンがちょっと古いなら、こんなオプションでも可能みたい。
$ sort -n -t '.' -k1,1 -k2,2 -k3,3 -k4n,4 sample.txt
1.1.1.1
1.2.3.4
3.5.7.9
7.6.5.4
7.10.5.4
9.8.7.6
20.10.5.3
60.70.80.90
150.150.150.150

Bash (CSV のIPアドレスソート(PHP ip2long を利用))

対象のリストが CSV 形式のうえ、ドットが別の場所にあったりすると最悪です。

sampel2.txt
example.jp,1.2.3.4
example.com,1.1.1.1
example.co.jp,20.10.5.3
work.example.jp,3.5.7.9
auction.example.com,7.10.5.4
www.example.jp,60.70.80.90
ftp.example.jp,9.8.7.6
mail.example.jp,150.150.150.150
auction.example.jp,7.6.5.4
こんなドメイン+IPアドレスになったりすると、上記のソートは使えませんね。
実際に試してみました。
$ sort --version-sort sample2.txt
auction.example.com,7.10.5.4
auction.example.jp,7.6.5.4
example.com,1.1.1.1
example.co.jp,20.10.5.3
example.jp,1.2.3.4
ftp.example.jp,9.8.7.6
mail.example.jp,150.150.150.150
work.example.jp,3.5.7.9
www.example.jp,60.70.80.90
IPアドレスでソートしたいのに、IPアドレスではなくドメインでのソートになっています。

ということで、キレイではありませんが*1ロングIPアドレスをリストに付与して並べるようにしてみます。
$ unset list
$ for i in $(cat sample2.txt)
do
  tmp=$(echo $i | cut -d ',' -f 2)
  tmp2=$(php -r 'echo sprintf ("%u", ip2long("$argv[1]"));' $tmp)
  list=$(printf '%s\n%s,%u' "$list" $i $tmp2)
done
$ echo "$list" | sort -t ',' -n -k3 | grep -v "^$"
example.com,1.1.1.1,16843009
example.jp,1.2.3.4,16909060
work.example.jp,3.5.7.9,50661129
auction.example.jp,7.6.5.4,117835012
auction.example.com,7.10.5.4,118097156
ftp.example.jp,9.8.7.6,151521030
example.co.jp,20.10.5.3,336200963
www.example.jp,60.70.80.90,1011241050
mail.example.jp,150.150.150.150,2526451350
ここでは PHP のワンライナーを使ってますが、php コマンドが使えない場合はオクテット毎に桁の重みを計算しないとダメでしょうね。

Bash (CSV のIPアドレスソート(AWK を利用))

変化形として awk で計算してみます。

まずは、計算できるか確認……
$ awk -F '.' '{a=0;b=0;c=0;d=0;for(i=1;i<=NF;i++){a=$1*256*256*256;b=$2*256*256;c=$3*256;d=$4}; printf "%u\n", a+b+c+d}' sample.txt
16909060
16843009
336200963
50661129
118097156
1011241050
151521030
2147483647
117835012
$ # もしくは
$ awk -F '.' '{a=0;b=0;c=0;d=0;for(i=1;i<=NF;i++){a=$1*256^3;b=$2*256^2;c=$3*256;d=$4}; printf "%u\n", a+b+c+d}' sample.txt
16909060
16843009
336200963
50661129
118097156
1011241050
151521030
2147483647
117835012
$ # もう少し短くできそう
$ awk -F '.' '{a=0;for(i=1;i<=NF;i++){a=$1*256^3+$2*256^2+$3*256+$4}; printf "
%u\n", a}' sample.txt
16909060
16843009
336200963
50661129
118097156
1011241050
151521030
2147483647
117835012
できたので組み込んでみます。
$ unset list
$ for i in $(cat sample2.txt)
do
  tmp=$(echo $i | cut -d ',' -f 2)
  tmp2=$(echo $tmp | awk -F'.' '{a=$1*256^3+$2*256^2+$3*256+$4}{printf "%u", a}')
  list=$(printf '%s\n%s,%u' "$list" $i $tmp2)
done
$ echo "$list" | sort -t ',' -n -k3 | grep -v "^$"
example.com,1.1.1.1,16843009
example.jp,1.2.3.4,16909060
work.example.jp,3.5.7.9,50661129
auction.example.jp,7.6.5.4,117835012
auction.example.com,7.10.5.4,118097156
ftp.example.jp,9.8.7.6,151521030
example.co.jp,20.10.5.3,336200963
www.example.jp,60.70.80.90,1011241050
mail.example.jp,150.150.150.150,2147483647
……なんとなく、awk だけでも IP アドレスでソートできそうな予感をひしひしと感じてたりしますが、ここでは考えません。
(Separator を2つ、個別に指定する方法が思い浮かびません……)

余分なロングIPアドレス列を消したい場合は、そのまま cut するとよいですかね。
$ echo "$list" | sort -t ',' -n -k3 | grep -v "^$" | cut -d "," -f 1,2
example.com,1.1.1.1
example.jp,1.2.3.4
work.example.jp,3.5.7.9
auction.example.jp,7.6.5.4
auction.example.com,7.10.5.4
ftp.example.jp,9.8.7.6
example.co.jp,20.10.5.3
www.example.jp,60.70.80.90
mail.example.jp,150.150.150.150

*1 : というかかなりキタナイ……。シェルスクリプトなのに、書いてあることを理解できる人は少ないのではなかろうか……

Windows 編

Excel

基本的には、IPアドレスをロングIPアドレスに変換して、Excel のソート機能「並べ替えとフィルター」で昇順に並べ替えます。
  • A1をアクティブセルにして、sample.txt の内容を貼り付けます。
  • B1セルに、つぎの内容を入力します。
=LEFT(A1,SEARCH(".",A1,1)-1)*(256*256*256)+MID(A1,SEARCH(".",A1,1)+1,SEARCH(".",A1,SEARCH(".",A1,1)+1)-SEARCH(".",A1,1)-1)*(256*256)+MID(A1,SEARCH(".",A1,SEARCH(".",A1,1)+1)+1,SEARCH(".",A1,SEARCH(".",A1,SEARCH(".",A1,1)+1)+1)-SEARCH(".",A1,SEARCH(".",A1,1)+1)-1)*256+MID(A1,SEARCH(".",A1,SEARCH(".",A1,SEARCH(".",A1,1)+1)+1)+1,SEARCH(".",A1,SEARCH(".",A1,SEARCH(".",A1,1)+1)+1)-SEARCH(".",A1,SEARCH(".",A1,1)+1)-1)
この関数、やっていることは . の位置を調べて mid で数値を抜き出し、各オクテットの重みを掛けてロングIPアドレスを算出しています。
  • B1セルの右下隅をダブルクリックして、数式をコピペ(オートフィル)します。
  • B列のどこかのセルをクリックしてオートフィルを利用した後の範囲指定状態を解除します。
  • 「並べ替えとフィルター」で昇順に並べ替えます。

その他

IPv6 は?

IPv6 は変数にいれるのも大変なので、なかなか難しいもよう。

IPv4 は 32bit なので、符号なし int なら何とか扱える感じ。
実際、符号あり int で計算しようとすると負の値になってしまうので、このページで使ってる printf / sprintf でも %u を指定しているのは、そのため。

128bit を格納する変数って、スクリプトだとどうやるんだろう?
誰か教えて!