DB設計:

エンティティ(実体)

例:美容院 予約システム

  1. 画面図などを使って、仕様を決める

  2. 画面図や仕様書を見ながら、何をデータとして保存するか列挙していく。
    列挙したデータを種類ごとに分ける。

    • 店名
    • 時間帯
    • 美容師
    • コース
    • システム側が事前に用意するもの

      • 店名
      • 美容師
    • ユーザーが登録するもの

      • 時間帯
      • コース
  3. 列挙したデータを抽象化して、エンティティとしてまとめる。

    • 店名ID:
    • 美容師No:

    • 時間帯:
    • コース:
  4. テーブル名と列名を定義し、データを入れる

クロエ(店名)テーブル
+--------+--------------+-------+
| 美容師ID|    時間帯     | コース |
+--------+--------------+-------+
| 1      | 9:00 ~ 18:00 | カット |
| 2      |10:00 ~ 19:00 | カラー |

SQL:言語化してみた

SELECT
  COUNT(*)
FROM
  employees;

言語化すると =>
 employees テーブルにおいて、いくつ行数があるか、数える
SELECT
  COUNT(*)
FROM
  current_dept_emp
WHERE
  to_date = '9999-01-01';

言語化すると =>
 current_dept_emp テーブルにおいて、to_date 値が、9999-01-01 と一致する
行数がいくつあるか、数える
SELECT
  emp_no,
  MAX(salary)
FROM
  salaries
GROUP BY
  emp_no
ORDER BY
  MAX(salary) DESC
LIMIT 30
;

言語化すると => 
 salariesテーブルにおいて、emp_no ごとに区切って、
その中で salaryの最大値を降順(大きい順)に並び替えて、30行抽出する。
SELECT
  e.emp_no,
  e.first_name,
  e.last_name,
  t.title
FROM
  employees AS e
  INNER JOIN titles AS t
    ON e.emp_no = t.emp_no
WHERE
  e.emp_no BETWEEN 10010 AND 10100
  AND t.to_date = '9999-01-01'
;

言語化すると => 
 employeesテーブルと、titles テーブル を emp_no で結合して、
emp_no が、10010 ~ 10100 の間 かつ、to_date が、9999-01-01 と一致する
レコード(行)を抽出する。
ただし、列は、emp_no, first_name, last_name, titles 
SELECT
  cde.*,
  d.dept_name
FROM
  current_dept_emp AS cde
  INNER JOIN departments AS d
    ON cde.dept_no = d.dept_no
;

言語化すると => 
 current_dept_empテーブル(cde)と、departments(d)テーブル を dept_no で結合して、
cde の列名 全て(cde.*) と、d の列名にある dept_name の列を抽出する。
SELECT
  dept_name,
  MAX(salary)
FROM
  current_dept_emp AS cde
  INNER JOIN departments AS d
    ON cde.dept_no = d.dept_no
  INNER JOIN salaries AS s
    ON cde.emp_no = s.emp_no
WHERE
  cde.to_date = '9999-01-01'
GROUP BY
  d.dept_name
LIMIT 10;

言語化すると => 
 current_dept_empテーブルと、departmentsテーブル を共通する dept_no で結合して
さらに、その結合されたテーブルと、salariesテーブルを 共通する emp_no で、結合する。
その上で、current_dept_empテーブルの to_date が、 '9999-01-01' と一致するレコードを取得する。
また、departmentsテーブルの1つの要素である dept_name で区切って、その中で、
salary の最大値 と dept_name の2列で、抽出する。ただし、10行以内で。
SELECT
  dm.*,
  d.dept_name,
  s.salary
FROM
  dept_manager AS dm
  INNER JOIN departments AS d
    ON dm.dept_no = d.dept_no
  INNER JOIN salaries AS s
    ON dm.emp_no = s.emp_no
WHERE
  dm.to_date = '9999-01-01'
  AND s.to_date = '9999-01-01'
;

言語化すると => 
 dept_managerテーブル(dm)と、departmentsテーブル(d) を共通する dept_no で結合して
さらに、その結合されたテーブルと、salariesテーブル(s)を 共通する emp_no で、結合する。
また、dm テーブル の to_date 値が、9999-01-01 と一致、かつ、
s テーブルの to_date 値が、9999-01-01 と一致するレコードを取得する。
最後に、dm テーブルの列全てと、dテーブルの dept_name 列、sテーブルの salary 列 を抽出する。

SQL:相関サブクエリ, コメント

### SQL 読み込まれる順番

1. FROM: クエリの対象となるテーブル(またはビュー)を指定
2. WHERE: 条件に基づいて行を取得
3. GROUP BY: グループ化の基準となる列を指定
4. HAVING: GROUP BY で取得した結果をさらに 絞る
5. SELECT: フィルタリングおよびグループ化されたデータから必要な列を選択
6. ORDER BY: 結果の並べ替え。 ASC, DESC など
7. LIMIT(またはTOPなど): 取得する行を指定し制限する
SQL分の中でのコメントの書き方
1. 
/*
上下2つの記号(/**/)を使って、挟んだ範囲が、
コメントになる
*/

2.
-- ここがコメントになる。

ハイフン2つ + 半角スペース1つ

3.
# シャープの横が、コメントになる。

シャープ1つ + 半角スペース1つ

例:
/*
給与が平均以上の従業員番号
*/
SELECT
  DISTINCT(emp_no) -- 従業員番号の重複を排除
FROM
  salaries # 給与テーブル
WHERE
  salary >= salary の平均値
LIMIT 10;

相関サブクエリ

・ salary が平均以上の emp_no を取得する

SELECT
  DISTINCT(emp_no)
FROM
  salaries
WHERE
  salary >= (
              SELECT
                AVG(salary)
              FROM
                salaries
            )
LIMIT 10;

上記は、以下を意味している。

SELECT
  DISTINCT(emp_no)
FROM
  salaries
WHERE
  salary >= salary の平均値
LIMIT 10;
  • DISTINCT(emp_no):emp_no の重複を除外して、ユニークな emp_no のみにしている。

  • 平均の2倍以上 :AVG(salary) * 2

番号 10001 ~ 10100 の中で、それぞれの性別で最高年齢の人の性別、
誕生日、first_name, last_name を抽出する。


SELECT
  gender,
  birth_date,
  first_name,
  last_name
FROM
  employees AS e1
WHERE
  emp_no BETWEEN 10001 AND 10100
  AND birth_date =  (
                      SELECT
                        MIN(birth_date)
                      FROM
                        employees AS e2
                      WHERE
                        emp_no BETWEEN 10001 AND 10100
                        AND e1.gender = e2.gender
                      GROUP BY gender
                    )
;

+--------+------------+------------+-------------+
| gender | birth_date | first_name | last_name   |
+--------+------------+------------+-------------+
| F      | 1952-04-19 | Sumant     | Peac        |
| M      | 1952-02-27 | Remzi      | Waschkowski |
+--------+------------+------------+-------------+
2 rows in set
employees テーブルの中で、emp_no が 10,001 ~ 10,100 の中で、かつ
それぞれのジェンダーの中で、誕生日が1番古いの を抽出する

mysql> SELECT
    ->   MIN(birth_date),
    ->   gender
    -> FROM
    ->   employees
    -> WHERE
    ->   emp_no BETWEEN 10001 AND 10100
    -> GROUP BY gender
    -> ;
+-----------------+--------+
| MIN(birth_date) | gender |
+-----------------+--------+
| 1952-02-27      | M      |
| 1952-04-19      | F      |
+-----------------+--------+
2 rows in set
各従業員の最高給与の上位30位の従業員番号と最高給与金額を求めよう

SELECT 
  emp_no,
  salary
FROM 
  salaries
WHERE 
  salary IN (
              SELECT 
                DISTINCT(salary)
              FROM 
                salaries
              ORDER BY 
                salary DESC
            )
ORDER BY 
  salary DESC
LIMIT 30;
+--------+--------+
| emp_no | salary |
+--------+--------+
|  43624 | 158220 |
|  43624 | 157821 |
| 254466 | 156286 |
...
...
...
| 266526 | 151080 |
| 237542 | 150994 |
| 493158 | 150993 |
+--------+--------+
30 rows in set

SQL:テーブル結合

テーブル結合

  • INNER JOIN:内部結合(共通部分のみ)

データがある列のみ結合
外部結合より、高速

$ SELECT <列名>, ...
  FROM <テーブル名1> INNER JOIN <テーブル名2>
    ON <テーブル名1.列名> = <テーブル名2.列名>;

AS構文:
hoge AS a これの意味は、hoge を a と名づける。


例:
$ SELECT *
   FROM hoge AS a INNER JOIN piyo AS b
    ON a.columnA = b.columnB;
  • LEFT OUTER JOIN:外部結合(元のテーブルと結合先の共通部分)

データがない列の値は、「NULL」にして結合

$ SELECT <列名>, ...
  FROM <テーブル名1> LEFT OUTER JOIN <テーブル名2>
    ON <テーブル名1.列名> = <テーブル名2.列名>;

・ LEFT OUTER JOIN テーブル名1 が元のテーブルになる。
・ RIGHT OUTER JOIN テーブル名2 が元のテーブルになる。

例:
$ SELECT *
   FROM hoge AS a 
    LEFT OUTER JOIN piyo AS b
      ON a.columnA = b.columnB;
mysql>  SELECT
    ->   e.emp_no,
    ->   e.first_name,
    ->   e.gender,
    ->   d.dept_no
    -> FROM
    ->   employees AS e INNER JOIN dept_manager AS d
    ->     ON e.emp_no = d.emp_no
    -> ;
+--------+-------------+--------+---------+
| emp_no | first_name  | gender | dept_no |
+--------+-------------+--------+---------+
| 110022 | Margareta   | M      | d001    |
| 110039 | Vishwani    | M      | d001    |
| 110085 | Ebru        | M      | d002    |
| 110114 | Isamu       | F      | d002    |
| 110183 | Shirish     | F      | d003    |
| 110228 | Karsten     | F      | d003    |
| 110303 | Krassimir   | F      | d004    |
| 110344 | Rosine      | F      | d004    |
| 110386 | Shem        | M      | d004    |
| 110420 | Oscar       | M      | d004    |
| 110511 | DeForest    | M      | d005    |
| 110567 | Leon        | F      | d005    |
| 110725 | Peternela   | F      | d006    |
| 110765 | Rutger      | F      | d006    |
| 110800 | Sanjoy      | F      | d006    |
| 110854 | Dung        | M      | d006    |
| 111035 | Przemyslawa | M      | d007    |
| 111133 | Hauke       | M      | d007    |
| 111400 | Arie        | M      | d008    |
| 111534 | Hilary      | F      | d008    |
| 111692 | Tonny       | F      | d009    |
| 111784 | Marjo       | F      | d009    |
| 111877 | Xiaobin     | F      | d009    |
| 111939 | Yuchang     | M      | d009    |
+--------+-------------+--------+---------+
24 rows in set
SELECT
  d.dept_name,
  e.first_name,
  e.last_name,
  dm.from_date,
  dm.to_date
FROM
  departments AS d
  INNER JOIN dept_manager AS dm
    ON d.dept_no = dm.dept_no
  INNER JOIN employees AS e
    ON dm.emp_no = e.emp_no
;

解説:
d テーブル の dept_no と dm テーブル の dept_no の共通部分をもつレコードを抽出。
さらに、
dm の emp_no と e テーブルの emp_no の共通部分をもつレコードを抽出。

その上で、以下の列を表示する
d.dept_name,
e.first_name,
e.last_name,
dm.from_date,
dm.to_date

+--------------------+-------------+--------------+------------+------------+
| dept_name          | first_name  | last_name    | from_date  | to_date    |
+--------------------+-------------+--------------+------------+------------+
| Customer Service   | Tonny       | Butterworth  | 1985-01-01 | 1988-10-17 |
| Customer Service   | Marjo       | Giarratana   | 1988-10-17 | 1992-09-08 |
| Customer Service   | Xiaobin     | Spinelli     | 1992-09-08 | 1996-01-03 |
| Customer Service   | Yuchang     | Weedman      | 1996-01-03 | 9999-01-01 |
| Development        | DeForest    | Hagimont     | 1985-01-01 | 1992-04-25 |
| Development        | Leon        | DasSarma     | 1992-04-25 | 9999-01-01 |

Git stash

$ git stash:一時的に避難して、他のブランチで作業をしたい時に使う。

$ git commit前に、$ git stashを打つ

$ git stash list:git stash した作業 一覧を表示するコマンド
$ git stash apply:最新の作業 を復元する

特定の作業を復元:$ git stash apply [stash名]

$ git stash drop:最新の作業 を削除する

特定の作業を削除:$ git stash drop [stash名]

全ての作業を復元:$ git stash clear

% git st
On branch main
Changes not staged for commit:

        modified:   home.html

no changes added to commit (use "git add" and/or "git commit -a")

% git stash  ※ <- ここ!!!
Saved working directory and index state WIP on main: ecd53dd third.htmlを追加

% git stash list  ※ <- ここ!!!
stash@{0}: WIP on main: ecd53dd third.htmlを追加

% git stash apply  ※ <- ここ!!!
On branch main
Changes not staged for commit:

        modified:   home.html

no changes added to commit (use "git add" and/or "git commit -a")

% git stash list
stash@{0}: WIP on main: ecd53dd third.htmlを追加
% git stash drop  ※ <- ここ!!!
Dropped refs/stash@{0} (b68a24367c928c407bda2e40d9d127316740bdb9)
% git stash list
% 

% git checkout home.html  ※ <- ここ!!!:home.html という変更を無かったことにする
Updated 1 path from the index
% git st                
On branch main
nothing to commit, working tree clean

SQL:SELECT 構文 part2

ORDER BY 句:検索結果を並び替える

$ SELECT * FROM employees ORDER BY <整列キー> <ASC/DESC>;

  • ASC は、省略可能。デフォルト値のため。

また、複数条件を指定することも可能

$ SELECT *
  FROM employees
  ORDER BY birth_date DESC, hire_date ASC;

誕生日が大きい(=年齢が若い)順、かつ、入社日が古い順に並び替える
集計関数(集約関数):

SUM, MIN, MAX, AVG, COUNT

  • COUNT:行数を取得する

    • COUNT(列名):NULL を除く

    • COUNT(*):NULL を含む

  • 四捨五入:ROUND(四捨五入する値, 小数第 X 位) X = 0 ~

  • WHERE 句では、集積関数は、使えない

読み込まれる順番:FROM -> WHERE -> SELECT

GROUP BY:テーブルを切り分けるイメージ
  • 集計関数と一緒に、使われることが多い。

  • GROUP BY で指定した 列以外を SELECT では指定できない。
    なぜなら、GROUP BY の後に、SELECT 句が読み込まれるから。

各emp_no が何回登場しているかを表わしている。

mysql> SELECT
    ->   emp_no,
    ->   COUNT(*)
    -> FROM
    ->   salaries
    -> GROUP BY
    ->   emp_no
    -> LIMIT 20;
+--------+----------+
| emp_no | COUNT(*) |
+--------+----------+
|  10001 |       17 |
|  10002 |        6 |
|  10003 |        7 |
|  10004 |       16 |
|  10005 |       13 |
|  10006 |       12 |
|  10007 |       14 |
|  10008 |        3 |
|  10009 |       18 |
|  10010 |        6 |
|  10011 |        7 |
|  10012 |       10 |
|  10013 |       17 |
|  10014 |        9 |
|  10015 |        1 |
|  10016 |        5 |
|  10017 |       10 |
|  10018 |       16 |
|  10019 |        4 |
|  10020 |        5 |
+--------+----------+
20 rows in set


例:従業員番号10001から10010の従業員ごとの最小給与と最大給与

mysql> SELECT
    ->   emp_no,
    ->   MAX(salary),
    ->   MIN(salary)
    -> FROM
    ->   salaries
    -> WHERE
    ->   emp_no BETWEEN 10001 AND 10010
    -> GROUP BY
    ->   emp_no
    -> LIMIT 20;
+--------+-------------+-------------+
| emp_no | MAX(salary) | MIN(salary) |
+--------+-------------+-------------+
|  10001 |       88958 |       60117 |
|  10002 |       72527 |       65828 |
|  10003 |       43699 |       40006 |
|  10004 |       74057 |       40054 |
|  10005 |       94692 |       78228 |
|  10006 |       60098 |       40000 |
|  10007 |       88070 |       56724 |
|  10008 |       52668 |       46671 |
|  10009 |       94443 |       60929 |
|  10010 |       80324 |       72488 |
+--------+-------------+-------------+
10 rows in set
HAVING 句:GROUP BY で取得した結果をさらに 絞る
 $ SELECT emp_no, MAX(salary)
  FROM salaries
  GROUP BY emp_no
  HAVING MAX(salary) > 100000;


解説:
emp_no 10001 ~ 10100 の中で、salaryの最小値が、40,000未満の
emp_no と 最小値 を抽出する。

SELECT
  emp_no,
  MIN(salary)
FROM
  salaries
WHERE
  emp_no BETWEEN 10001 AND 10100
GROUP BY
  emp_no
HAVING
  MIN(salary) > 40000
LIMIT 20;

スマホ買うなら、セキュリティアップデート保証期限を気にしよう!

pixel 3a 使ってますが、2022年の春に保証期限が終了してました。。。
とはいえ、次買うのは、ストレージの容量的には、2024年の夏になるだろうなと。

5a を次は、購入しようと考えていましたが、アップデート保証期限が、
2024 年 8 月
のため、無しですね。購入と同時に、保証が切れます()

                  Android update    セキュリティ update 
Google Pixel 6a     2025 年 7 月        2027 年 7 月

なので、6a かな〜と。