---
# System prepended metadata

title: Ruby(08/14) 五倍紅寶石(第八屆共筆)(2021/8/13)
tags: [Rails, DataBase, Ruby]

---

# Ruby(08/14) 五倍紅寶石(第八屆共筆)(2021/8/13)
## Rails-HW
25 mins 內

model: Product
- 商品名稱
- 價錢
- 商品描述
- 是否上架

Product CRUD

- 錄影，可不講解

## Database
寫 Rails 語法時可試著回想資料庫語法是甚麼。
如果要增加或調整資料庫欄位，建議用 Rails 去改不要手動去資料庫調。
文字資料要用引號包起來，數字資料不用。

- 多餘的單引號：
  在單引號前面多加一個反斜線\  是跳脫符號，讓他能正常顯示，不然會被判定為一般引號。

### DDL Data Definition Language
資料定義語言
CREATE 建立資料庫的物件
ALTER 變更資料庫的物件
DROP 刪除資料庫的物件

### DML Data Manipulation Language
資料操作語言
INSERT 新增資料到資料表中
UPDATE 更改資料表中的資料
DELETE 刪除資料表中的資料

### DQL Data Query Language
資料查詢語言
SELECT 選取資料庫中的資料

### DCL Data Control Language
資料控制語言
GRANT 賦予使用者使用權限
REVOKE 取消使用者的使用權限
COMMIT 完成交易作業
ROLLBACK 交易作業異常，將已變動的資料回復到交易開始的狀態

- 追加欄位：
  ALTER TABLE heroes
  ADD COLUMN super_power VARCHAR(100);
  = add_column :heroes, :super_power, :string
  
- 刪除欄位：
  ALTER TABLE heroes
  DROP COLUMN super_power;
  = remove_column :heroes, :super_power, :string
  
- 刪除資料表：
  DROP TABLE heroes;
  = drop_table :heroes

- 新增資料：
  INSERT INTO heroes
  (name, gender, age, hero_level, hero_rank, description)
  VALUES
  ("竈門炭治郎", "M", 15, "S", 10, 鬼殺隊的一員，為了拯救妹妹，決定要打敗無慘，會使用水之呼吸、日之呼吸以及全集中呼吸。)
  可省略欄位名稱不寫，或是只寫部分欄位
  
- 選取資料：
  - 選全部欄位的特定英雄：
    SELECT * 
    FROM heroes
    WHERE hero_level = "S" AND gender = "F";
    = Hero.where(level: "S",gender = "F")
    
  - 只選特定欄位，做更精準的控制：
    把 * 換掉，消耗的記憶體相對比較少
    SELECT name, gender
    FROM heroes
    WHERE hero_level = "S" AND gender = "F";
    = Hero.select(:name, :gender).where(level: "S",gender = "F")

  - 找到沒有填的欄位：
    SELECT *
    FROM heroes
    WHERE age IS NULL;

  - 找特定字元，搜尋名字內有背心的英雄：
    SELECT *
    FROM heroes
    WHERE name LIKE "%背心%";
    = Hero.where("name like "%背心%"")
    = Hero.where(['name like "%?%"', keyword])
    
    %背心 = xxx背心
    背心% = 背心xxx
    %背心% = xxx背心xxx

  - 找年鄰 10~25之間：
    方法一:
    SELECT *
    FROM heroes
    WHERE age >= 10 AND age <=25;
    
    方法二:
    SELECT *
    FROM heroes
    WHERE age BETWEEN 10 AND 25;

    = Hero.where("age >= 10 and age <= 25")
    = Hero.where("age >= 10")
          .where("age <= 25")
    = Hero.where(age: 10..25)

  - 是 A 跟 S 級的:
    方法一:
    SELECT *
    FROM heroes
    WHERE hero_level = "A" OR hero_level = "S";

    方法二:
    SELECT *
    FROM heroes
    WHERE hero_level IN ("S", "A");

  - 不是 S 級的:
    方法一:
    SELECT *
    FROM heroes
    WHERE hero_level  NOT IN ("S");

    方法二:
    SELECT *
    FROM heroes
    WHERE hero_level<>"S";

  - 不是 S 跟 A 級的:
    SELECT *
    FROM heroes
    WHERE hero_level  NOT IN ("S", "A");

  - 列出所有 A 級男性英雄的姓名以及年齡:
    SELECT age , name
    FROM heroes
    WHERE hero_level  IN ("A") AND gender IN ("M");

- 更新資料：
  - 把編號 25 號的英雄改成 10 歲
    UPDATE heroes
    SET age =10
    WHERE id = 25;
    = Hero.find(25).update(age: 10)            (現在用法)
    = Hero.find(25).update_attributs(age: 10)  (早期用法)
    = h = Hero.find(25)
      h.age = 25
      h.save
    記得要加 where 不然會全部改掉

- 刪除資料：
  清空資料表內的資料，跟 DROP 不一樣，DROP 是直接刪掉資料庫或資料表
  - 刪除 C 級英雄：
    DELETE FROM heroes
    WHERE hero_level = "C"

  - 刪除排名第三的 S 級英雄：
    DELETE FROM heroes
    WHERE hero_level = "S" AND hero_rank = 3 ;

- 計算總數：
  SELECT COUNT(*)
  FROM heroes
  WHERE hero_level = "A" ;

- 加總：
  SELECT SUM(age)
  FROM heroes
  WHERE hero_level = "A" AND age IS NOT NULL;
  = total = Hero.sum(:age)
  給資料庫去算就好，不要用 Ruby 轉圈圈算，這是 Ruby 的弱項

- 平均：
  SELECT AVG(age)
  FROM heroes
  WHERE hero_level = "A" AND age IS NOT NULL;

- 最大值：
  SELECT MAX(age)
  FROM heroes ;

- 最小值：
  SELECT MIN(age)
  FROM heroes ;

- 分組：
  - 計算每個等級英雄的年齡總合
    SELECT hero_level, SUM(age) as "總和",AVG(age) as "平均"
    FROM heroes
    GROUP BY hero_level ;
  
    as 可以改欄位名稱
    GROUP BY 是高級版的 DISTINCT

  - 有哪些等級：
    SELECT DISTINCT hero_level
    FROM heroes ;
    可應用在下拉選單做分類

- 排序：
  - 正向：
    SELECT *
    FROM heroes
    WHERE hero_level = "S"
    ORDER BY hero_rank ;
    = Hero.where(hero_level: "S").order(:hero_rank)

  - 反向：
    SELECT *
    FROM heroes
    WHERE hero_level = "S"
    ORDER BY age DESC;
    = Hero.where(hero_level: "S").order(hero_rank: :desc)

- 取前三名：
  SELECT *
  FROM heroes
  WHERE hero_level = "S"
  ORDER BY hero_rank
  LIMIT 3 ;

- 組合技：
  - 找出被埼玉打倒的反派
    SELECT *
    FROM monsters
    WHERE kill_by = 
    ( 
    SELECT id
    FROM heroes
    WHERE name = "埼玉" 
    );
  
  - 找出被埼玉跟傑諾斯打倒的反派
    SELECT *
    FROM monsters
    WHERE kill_by IN
    ( 
    SELECT id
    FROM heroes
    WHERE name IN ("埼玉", "傑諾斯")
    );

- 主鍵PK：
  是某個資料表的一個欄位
  每個資料表都要有一個
  獨一無二的值
  不能是 NULL

- 外部鍵FK：(kill_by)
  是某個資料表的一個欄位
  參照到另一個欄位的主鍵
  用來確認兩個資料表間的資料可以對的起來
  不用獨一無二
  可以是 NULL

  建立外部鍵：(建議要做！ 保持資料的完整性，最基本的)
  可以用 MySQLWorkbench：圖形介面工具來操作
  表格下面有 foreign key 可點選
  設定 Referenced 
  On Update : cascade
  On Delete : Restrict
  
  CASCADE: 更新或刪除主鍵的資料時，也更新或刪除外部鍵這邊資料。
  SET NULL: 更新或刪除主鍵的資料時，將外部鍵這邊資料設定為 NULL。
  RESTRICT: 如果外部鍵這邊有資料，禁止更新或刪除主鍵資料。
  NO ACTION: 不做動作(不建議)。

- 交集：
  inner / left / right

  - Inner Join:兩個都有
  - Left Join:左邊為主 + 兩個都有
  - Right Join:右邊為主 + 兩個都有

  - 把 t2 加到 t1 資料表：
    因為沒給他條件，總數會變 t1 * t2 
    SELECT *
    FROM t1
    JOIN t2
  
  - Left Join:
    以左邊為主，左邊全列出，右邊有的就列，沒有就null：
    SELECT *
    FROM t1
    LEFT JOIN t2
    ON t1.username = t2.name ;

  - Inner Join:
    兩邊都有的才列出：
    SELECT *
    FROM t1
    INNER JOIN t2
    ON t1.username = t2.name ;

  - 找出被打敗的反派
    SELECT m.name, h.name
    FROM monsters as m
    INNER JOIN heroes as h
    ON m.kill_by = h.id 
    WHERE m.kill_by IS NOT NULL ;

  - 找出被 S 級英雄打敗的反派：
    SELECT m.name as "反派", h.name as "英雄"
    FROM monsters as m
    INNER JOIN heroes as h
    ON m.kill_by = h.id
    WHERE h.hero_level = "S";
    = Hero.join(:monsters).where(...)

- ER 模型：
  Entity Relationship Model 實體關聯模型
  用 MySQLWorkbench 的 Reverse Engineer 可建立
  有空可匯入龍哥提供的 MySQL 檔玩玩

### Windows 安裝 SQL
MySQL:有分client、server端
client放windows
server放wsl

## 部屬
Docker:(有機會可以學一下，DevOps 工程師會用到)
一個虛擬化的技術，在原本系統內，虛擬化一個新的作業系統，裡面要安裝什麼系統都可以。
可以用 Docker 開一個貨櫃，整個丟到 server上面，讓每個人都可以直接使用。
解題網站會用到這個技術，就算被別人弄也沒關係，只會把 Docker 的虛擬化系統用壞，不會傷害到自己的系統。

## Rails
- migration檔 : change 方法
  change = up + down 的融合版
  用 change 建議還是要寫型態，這樣用 rollback 才知道要用什麼型態
  不像 up down 有前面的 up 可以做比對

- rails c --sandbox
  不會影響到原本資料，只會影響這個空間

- 在 Rails c 裡面打 .all，只會噴 11 筆資料，因為如果全部列出來會太多，使用者根本看不完。

---

[DB XMind](https://www.xmind.net/m/3QwcXi)

---

###### tags: `Ruby` `Rails` `DataBase`