在之前透過 Active Record Query 去探索在 Rails 裡是如何對資料庫找資料的,想想發現對於資料庫的基本觀念似乎還沒有講述,今天來點資料庫吧!
簡單來說,資料庫是用於有效地存儲、檢索和管理所有資料!
平時在詳列出自己的購物清單明細,其實這樣列點式出來就很像一個小型的資料庫,
一張紙上列出一筆筆購物項目,可以新增修改刪除。
而在電腦上的資料庫就是儲存在電腦系統上的資料資訊集合,例如書店的庫存資訊。
在資料庫中,資訊被組織成表格,每個表格包含一組列和行,每列表示一種類型的資料,每行包含一條特定的數據記錄。
隨著資料越來越龐大,想要讓資料保持井然有序、易於存取且安全無虞變得更為困難。
為了解決這些問題,就有了現在常聽到的資料庫管理系統 (DBMS)。而資料庫管理系統又是什麼?
想要有效率地使用與管理資料,能方便、有效使用資料庫的軟體,
就是資料庫管理系統 (Database Management System,簡稱 DBMS)。
資料庫管理系統能幫我們與資料庫做溝通,
其中包括關聯型資料庫管理系統(RDBMS)以及非關聯型資料庫 (NoSQL) 。
為什麼非關聯型資料庫稱為 NoSQL?
在關聯型資料庫管理系統 (RDBMS) 裡,通常使用結構化查詢語言,也就是 SQL 語法來管理和檢索資料;而非關聯型資料庫 (NoSQL) 通常不使用 SQL,而是使用不同的方法來存儲和檢索資料!
關聯型資料庫管理系統(RDBMS)
非關聯型資料庫 (NoSQL)
資料庫也可以分成
伺服器型資料庫
和檔案型資料庫
:
伺服器型資料庫 - 幾乎所有 RDBMS 都是伺服器型資料庫,資料庫需要先將資料庫安裝於電腦主機上才能使用。
檔案型資料庫 - 一個檔案本身就是一個資料庫,像是 SQLite 適合用在資料量較少,且不會有多人同時存取的情況。
在建立資料庫時,需要先針對需求以及規格去思考要建立哪些資料表以及資料表中所包含的資料型態,
甚至還有資料與資料之間的關聯,今天就來淺談這幾點吧!Let's go!
主鍵(Primary Key,PK)
外鍵(Foreign Key,FK)
主鍵用來唯一識別一個資料表中的每一筆資料,而外鍵用來建立資料表之間的關聯,確保資料的一致性。主鍵和外鍵在資料庫設計和資料表之間的連接中扮演著重要角色。
在建立資料表之前,我們要先來看看有哪些資料型態:
整數 (INTEGER):
小數 (DECIMAL/NUMERIC, FLOAT, DOUBLE):
字符 (CHAR, VARCHAR, TEXT):
CHAR
是固定長度的字符,而 VARCHAR
是可變長度的字符。日期和時間 (DATE, TIME, DATETIME, TIMESTAMP):
布林 (BOOLEAN):
枚舉 (ENUM):
二進制 (BINARY, BLOB):
CREATE TABLE Customers (
CustomerID INT PRIMARY KEY,
Customername VARCHAR(50) NOT NULL,
FirstName VARCHAR(50),
LastName VARCHAR(50),
Email VARCHAR(100) UNIQUE,
RegistrationDate DATE
);
CREATE TABLE Orders (
OrderID INT PRIMARY KEY,
CustomerID INT,
OrderDate DATE,
TotalAmount DECIMAL(10, 2),
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);
CREATE TABLE Products (
ProductID INT PRIMARY KEY,
ProductName VARCHAR(100) NOT NULL,
Price DECIMAL(10, 2),
Category VARCHAR(50)
);
上面我們看到了在建立資料表時,使用的 SQL 語法,
接著淺談一下,在 SQL 裡的基礎語法有哪些吧!
Remark:
每段最後同時寫上呼應的 Rails 語法,底下的 Hero 是 Model 喔!
SELECT 查詢資料
SELECT * -- 挑出所有欄位
FROM heroes;
-- Rails: Hero.all
SELECT *
FROM heroes
WHERE hero_level = 'S';
-- Rails: Hero.where(hero_level: 'S')
-- Method 1
SELECT *
FROM heroes
WHERE (hero_level, gender) = ('S', 'F');
-- Method 2
SELECT *
FROM heroes
WHERE hero_level = 'S';
AND gender = 'F';
-- Rails: Hero.where(hero_level: 'S', gender: 'F')
SELECT name, hero_level
FROM heroes
WHERE hero_level = 'S';
-- Rails: Hero.select(:name, :hero_level).where(hero_level: 'S')
SELECT *
FROM heroes
WHERE age is NULL;
-- Rails: Hero.where(age: nil)
SELECT *
FROM heroes
WHERE name LIKE '背心%' ;
-- Rails: Hero.where("name LIKE '%背心%'")
-- Method 1
SELECT *
FROM heroes
WHERE age BETWEEN 10 AND 25; -- 有包含 10 and 25
-- Method 2
SELECT *
FROM heroes
WHERE age > 10 AND age < 25;
-- Rails: Hero.where(age: 10...25)
-- Method 1
SELECT *
FROM heroes
WHERE hero_level IN ('S', 'A');
-- Method 2
SELECT *
FROM heroes
WHERE hero_level = 'S' OR hero_level = 'A';
-- Rails: Hero.where(hero_level: ['S', 'A'])
-- Method 1
SELECT *
FROM heroes
WHERE hero_level != 'S';
-- Method 2 用大於小於組合! SQL 專屬!
SELECT *
FROM heroes
WHERE hero_level <> 'S';
-- Rails: Hero.where.not(hero_level: 'S')
-- Rails: Hero.where("hero_level != 'S'")
SELECT *
FROM heroes
WHERE hero_level NOT IN ('S', 'A');
-- Rails: Hero.where.not(hero_level: ['S', 'A'])
SELECT name, age
FROM heroes
WHERE gender = 'M' AND hero_level = 'A';
UPDATE 更新資料
UPDATE heroes
SET age = 10
WHERE id = 25
UPDATE heroes
SET age = age + 1;
UPDATE heroes
SET hero_level = 'B' , hero_rank = 101
WHERE ID = 35;
DELETE 刪除資料
DELETE FROM
WHERE
進階查詢 - 計算總數
SELECT COUNT(*)
FROM heroes
WHERE hero_level = 'S';
-- Rails: Hero.where(hero_level: 'S').count
SELECT SUM(age)
FROM heroes
WHERE hero_level = 'A' AND age IS NOT NULL;
-- Rails: Hero.where(hero_level: 'A').sum
SELECT AVG(age)
FROM heroes
WHERE hero_level = 'A' AND age IS NOT NULL;
-- Rails: Hero.where(hero_level: 'A').where.not(age: nil).average(:age)
分組
SELECT hero_level, AVG(age)
FROM heroes
GROUP BY hero_level;
-- Rails: Hero.group(:hero_level).average(:age)
DISTINCT
在 SQL 中,DISTINCT 用於去除查詢結果中重複的行,使得查詢結果只包含唯一值。
挑出不同的級數:
SELECT DISTINCT danger_level
FROM monsters;
排序
-- 升冪排序
SELECT *
FROM heroes
WHERE hero_level = 'S'
ORDER BY hero_rank ASC;
-- 降冪排序
SELECT *
FROM heroes
WHERE hero_level = 'S'
ORDER BY hero_rank DESC;
SELECT *
FROM heroes
WHERE hero_level = 'S'
AND age IS NOT NULL -- 可以排除掉沒有的值
ORDER BY age;
SELECT *
FROM heroes
WHERE hero_level = 'S'
ORDER BY hero_rank
LIMIT 5; -- 限定數量
Remark:
蝦皮的捲軸分頁視窗:
如果 page = params[:page] || 1
```SQL
SELECT *
FROM items
ORDER BY id
LIMIT 6
OFFSET (page - 1) * 6;
```
INNER JOIN 兩者交集
LEFT JOIN 左邊為主對照右邊;RIGHT JOIN 右邊為主對照左邊
SELECT *
FROM t1
INNER JOIN t2
on t1.username = t2.name; -- 比對 t1 跟 t2 的相同名稱
SELECT monsters.name, heroes.name
FROM monsters
INNER JOIN heroes
on monsters.kill_by = heroes.id
WHERE kill_by IS NOT NULL;
簡化:
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;
透過 battle_histories 將資訊由 id 轉為 name:
SELECT h.name, m.name
FROM battle_histories as bh
INNER JOIN heroes as h
INNER JOIN monsters as m
on bh.hero_id = h.id AND bh.monster_id = m.id;
一種用來描述資料庫中資料實體和它們之間關係的視覺化工具。
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 ('埼玉', '傑諾斯')
)
資料庫和 Excel 是兩種不同的資料管理工具,在設計和使用上有很多差異:
資料庫適用於大型結構化資料的管理和處理,並且支援多用戶存取和複雜的查詢需求。
Excel 則適合用於較小的資料集,用於個人或小型組織的資料管理和分析。
今天就到這,我們下篇見!
文章同步於個人部落格:Viiisit!(歡迎參觀 ୧ʕ•̀ᴥ•́ʔ୨)