SQL(Structured Query Language)是結構化查詢語言,用於管理和操作關聯式數據庫。它是數據庫管理系統中使用最廣泛的語言之一。
-- 查詢數據
SELECT * FROM 表名 WHERE 條件;
-- 插入數據
INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2);
-- 更新數據
UPDATE 表名 SET 列1 = 值1 WHERE 條件;
-- 刪除數據
DELETE FROM 表名 WHERE 條件;
-- 創建表
CREATE TABLE 表名 (
列名1 數據類型,
列名2 數據類型
);
INT:整數類型。VARCHAR(n):變長字元串,最多 n 個字元。DATE:日期類型。FLOAT:浮點數類型。BOOLEAN:布林值(真或假)。MySQL 是一種流行的開源關聯式資料庫管理系統 (RDBMS),使用 SQL 作為查詢語言,適合中小型到大型應用程式。
mysql -u root -p
CREATE DATABASE example_db;
USE example_db;
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), age INT);
INSERT INTO users (name, age) VALUES ('Alice', 30);
SELECT * FROM users;
SQLite 是一種嵌入式資料庫,無需獨立伺服器進行管理,適合用於輕量級應用程式。
sqlite3 example.db
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);
INSERT INTO users (name, age) VALUES ('Alice', 30);
SELECT * FROM users;
name 欄位值是唯一的。name 欄位的長度適中,避免過長影響效能。如設定檔的類型資料表:
CREATE TABLE config_types (
name VARCHAR(50) PRIMARY KEY,
description TEXT
);
INSERT INTO config_types (name, description) VALUES ('general', 'General settings');
SELECT * FROM config_types WHERE name = 'general';
此表格將存放所有「動物」的通用屬性。
| 欄位名稱 | 資料型態 | 說明 |
|---|---|---|
| id | INT | 動物的唯一識別碼 |
| species | VARCHAR(50) | 動物的種類 |
| age | INT | 動物的年齡 |
此表格將繼承 animal 表格的 id,並儲存「貓」的特有屬性。
| 欄位名稱 | 資料型態 | 說明 |
|---|---|---|
| id | INT | 對應到 animal 表格的 id |
| breed | VARCHAR(50) | 貓的品種 |
| favorite_food | VARCHAR(50) | 貓的喜愛食物 |
CREATE TABLE animal (
id INT PRIMARY KEY AUTO_INCREMENT,
species VARCHAR(50) NOT NULL,
age INT NOT NULL
);
CREATE TABLE cat (
id INT PRIMARY KEY,
breed VARCHAR(50),
favorite_food VARCHAR(50),
FOREIGN KEY (id) REFERENCES animal(id)
);
INSERT INTO animal (species, age) VALUES ('Cat', 3);
INSERT INTO cat (id, breed, favorite_food) VALUES (1, 'Siamese', 'Fish');
| 動物ID | 種類 | 年齡 |
|---|---|---|
| 1 | Cat | 3 |
| 動物ID | 品種 | 喜愛食物 |
|---|---|---|
| 1 | Siamese | Fish |
在此範例中,animal 表格儲存了所有動物的共同屬性,而 cat 表格則儲存貓的特有屬性。cat 表格中的 id 是參照
animal 表格的 id,代表這是一種繼承關係。
SELECT * FROM animal;
這個查詢將返回所有貓的完整資料,包括繼承自 animal 表格的通用屬性。
SELECT animal.id, animal.species, animal.age, cat.breed, cat.favorite_food
FROM animal
JOIN cat ON animal.id = cat.id;
SELECT * FROM animal WHERE id = 1;
SELECT animal.id, animal.species, animal.age, cat.breed, cat.favorite_food
FROM animal
JOIN cat ON animal.id = cat.id
WHERE cat.breed = 'Siamese';
在這些查詢範例中,我們使用 JOIN 將 animal 表格和 cat
表格結合起來,以取得貓的完整資料。這種方法確保查詢結果包含繼承屬性與特有屬性。
FOREIGN KEY(外鍵)用於建立兩個資料表之間的關聯性,確保資料的參考完整性。例如,一個資料表的欄位值必須參考另一個資料表中的主鍵或唯一值。
CREATE TABLE 子資料表 (
欄位名稱 資料類型,
FOREIGN KEY (外鍵欄位) REFERENCES 父資料表(主鍵欄位)
);
建立一對多的關聯,例如訂單與客戶:
-- 建立父資料表 (customers)
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(50)
);
-- 建立子資料表 (orders) 並設定外鍵
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
PRIMARY KEY 或 UNIQUE。ON DELETE 行為。可以透過 ON DELETE 和 ON UPDATE 指定外鍵行為:
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CASCADE:同步刪除或更新子資料表中的相關資料。SET NULL:將子資料表中的外鍵欄位設為 NULL。RESTRICT:阻止刪除或更新,預設行為。NO ACTION:與 RESTRICT 類似,延遲約束檢查。在 MySQL 中,可以使用 COMMENT 來為欄位添加備註。
CREATE TABLE users (
id INT PRIMARY KEY COMMENT '使用者唯一識別碼',
name VARCHAR(50) COMMENT '使用者姓名',
age INT COMMENT '使用者年齡'
);
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT
) COMMENT = '使用者資料表';
可透過以下語法查詢欄位的備註:
SHOW FULL COLUMNS FROM users;
ALTER TABLE users MODIFY COLUMN name VARCHAR(50) COMMENT '修改後的備註';
COMMENT,但 SQLite 不支援。COMMENT ON 指令。COMMENT ON COLUMN users.name IS '使用者姓名';
在 SQL 查詢中,當欄位名稱與資料庫系統的保留字(Keyword)衝突時,會導致語法錯誤。處理這個問題需要從預防和解決兩個面向進行全面考量。
這是最推薦的做法,旨在從源頭消除問題。
interval 改為 time_interval,將 rank 改為 user_rank。當無法避免使用保留字時(例如:處理現有資料庫結構),必須使用適當的引號將欄位名稱包裹起來,以明確告知 SQL 引擎這是一個識別符號而非 SQL 命令。
| 資料庫系統 | 引號符號 | 範例 |
|---|---|---|
| MySQL / MariaDB | 反引號 (`) |
SELECT `interval`, `time` FROM table; |
| PostgreSQL / Oracle | 雙引號 (") |
SELECT "interval", "time" FROM table; |
| SQL Server | 方括號 ([]) |
SELECT [interval], [time] FROM table; |
在 Python 等程式語言中,若需要動態生成 SQL 語句,應實作一個函式來自動執行引號包裹,確保生成的語句安全且正確。
\b)來精確匹配欄位名稱,避免錯誤地替換字串值或較長的名稱。如果使用 ORM(例如 SQLAlchemy 或 Django ORM),框架會自動處理保留字和不同資料庫之間的引號差異,將底層的 SQL 輸出抽象化,這大大簡化了開發工作並提高了程式碼的穩定性。
計算兩個 DATETIME 欄位的時間差(單位:秒)。
SELECT * FROM table_name
WHERE TIMESTAMPDIFF(SECOND, datetime_column1, datetime_column2) < 5;
確保時間差為絕對值,避免順序影響。
SELECT * FROM table_name
WHERE ABS(TIMESTAMPDIFF(SECOND, datetime_column1, datetime_column2)) < 5;
若只需比較是否為同一天,可以使用 DATEDIFF。
SELECT * FROM table_name
WHERE DATEDIFF(datetime_column1, datetime_column2) = 0;
適用於支援時間戳記運算的資料庫,如 MySQL。
SELECT * FROM table_name
WHERE ABS(UNIX_TIMESTAMP(datetime_column1) - UNIX_TIMESTAMP(datetime_column2)) < 5;
您提供的數值 1763251200000 是一個標準的 **毫秒級時間戳**(Unix Epoch Time in milliseconds)。
MySQL 內建的函式(例如 FROM_UNIXTIME)預設處理的是 **秒級時間戳**。因此,您需要在使用前將毫秒級時間戳轉換為秒級。
將您的毫秒值除以 $1000$ 即可得到 MySQL 函式所需的秒級時間戳:
1763251200000 / 1000 = 1763251200
使用 FROM_UNIXTIME() 函式將秒級時間戳轉換為標準的 MySQL DATETIME 格式:
SELECT FROM_UNIXTIME(1763251200000 / 1000);
如果您的 MySQL 版本支援毫秒,並且您希望在結果中保留毫秒精度,您可以使用第二個參數:
SELECT FROM_UNIXTIME(1763251200000 / 1000, '%Y-%m-%d %H:%i:%s.%f');
其中:
%Y-%m-%d %H:%i:%s 是標準的日期時間格式。%f 捕獲微秒(Microseconds),因此您需要將剩餘的毫秒作為小數部分傳入。如果您的目的是將毫秒值儲存在一個整數(例如 INT 或 BIGINT)欄位中作為秒級時間戳,則只需要簡單的除法運算:
SELECT 1763251200000 / 1000;
或者,如果您的資料儲存在表格欄位中(例如欄位名為 timestamp_ms):
SELECT timestamp_ms / 1000 AS unix_timestamp_s FROM your_table;
當您將此值插入到具有 DATETIME 或 TIMESTAMP 型別的欄位時,您需要在 VALUES 部分執行轉換:
INSERT INTO your_table (datetime_column)
VALUES (FROM_UNIXTIME(1763251200000 / 1000));
FROM_UNIXTIME() 函式會將 UTC 時間戳轉換為您 MySQL 伺服器配置的時區。如果您的時間戳是基於 UTC,並且您希望結果也是 UTC,您需要確保您的伺服器或連線時區設置正確,或使用 CONVERT_TZ 函式進行明確的時區處理。
在 MySQL 中,可使用 FORMAT() 來格式化浮點數。
SELECT FORMAT(123.4567, 2); -- 結果: '123.46'
ROUND() 用於四捨五入至固定小數位數。
SELECT ROUND(123.4567, 2); -- 結果: 123.46
將 FLOAT 轉換為 DECIMAL 以保持固定小數位數。
SELECT CAST(123.4567 AS DECIMAL(10,2)); -- 結果: 123.46
SELECT CONVERT(123.4567, DECIMAL(10,2)); -- 結果: 123.46
SELECT id, FORMAT(price, 2) AS formatted_price FROM products;
建立資料表時可直接設定小數點位數。
CREATE TABLE products (
id INT PRIMARY KEY,
price DECIMAL(10,2) -- 兩位小數
);
取得欄位的最大值。
SELECT MAX(price) AS max_price FROM products;
取得欄位的最小值。
SELECT MIN(price) AS min_price FROM products;
計算欄位的平均值。
SELECT AVG(price) AS avg_price FROM products;
SELECT
MAX(price) AS max_price,
MIN(price) AS min_price,
AVG(price) AS avg_price
FROM products;
SELECT category,
MAX(price) AS max_price,
MIN(price) AS min_price,
AVG(price) AS avg_price
FROM products
GROUP BY category;
對另一個查詢結果求最大值。
SELECT MAX(price) FROM (SELECT price FROM products WHERE category = 'electronics') AS subquery;
排序後取最大值。
SELECT price FROM products WHERE category = 'electronics' ORDER BY price DESC LIMIT 1;
WITH filtered_products AS (
SELECT price FROM products WHERE category = 'electronics'
)
SELECT MAX(price) FROM filtered_products;
幾何平均數(Geometric Mean)計算公式:
GM = (x1 * x2 * ... * xn)^(1/n)
在 SQL 中,可以透過對數運算來計算幾何平均數。
SELECT EXP(AVG(LOG(price))) AS geometric_mean FROM products WHERE price > 0;
使用 POWER() 計算 n 次方根:
SELECT POWER(EXP(SUM(LOG(price))), 1 / COUNT(price)) AS geometric_mean
FROM products WHERE price > 0;
LOG() 會導致錯誤。SELECT EXP(AVG(LOG(price))) AS geometric_mean FROM products WHERE price > 0;
在 MySQL / MariaDB 中,可以使用 STDDEV() 來計算標準差。
SELECT STDDEV(salary) AS salary_stddev FROM employees;
SQL 提供兩種標準差計算方式:
STDDEV_POP() - 計算母體標準差(Population Standard Deviation)STDDEV_SAMP() - 計算樣本標準差(Sample Standard Deviation)SELECT
STDDEV_POP(salary) AS population_stddev,
STDDEV_SAMP(salary) AS sample_stddev
FROM employees;
如果 SQL 版本不支援 STDDEV(),可以使用以下公式:
SELECT SQRT(
SUM(POW(salary - (SELECT AVG(salary) FROM employees), 2)) / COUNT(salary)
) AS salary_stddev
FROM employees;
STDDEV() 可以直接計算標準差。STDDEV_POP() 計算母體標準差,STDDEV_SAMP() 計算樣本標準差。SQL 的 WHERE 子句用於從表格中提取那些符合指定條件的記錄(列/行)。它是資料操作語言(DML)中最基礎也最重要的部分之一,用於精確篩選所需的資料。
WHERE 子句在資料庫讀取表格時,對每一行(Row)進行評估。只有當某一行的資料滿足 WHERE 後面的條件時,該行才會被包含在結果集中。SELECT, UPDATE, DELETE 等 SQL 命令一起使用。WHERE 子句通常緊跟在 FROM 子句之後:
SELECT column_name(s)
FROM table_name
WHERE condition;
或用於修改或刪除資料時:
UPDATE table_name
SET column1 = value1
WHERE condition;
WHERE 子句中使用運算子來建立條件,最常見的有:
| 運算子類型 | 運算子 | 描述 |
|---|---|---|
| 比較運算子 | = |
等於 |
| 比較運算子 | >, <, >=, <= |
大於、小於、大於等於、小於等於 |
| 比較運算子 | <> 或 != |
不等於 |
| 邏輯運算子 | AND |
同時滿足多個條件 |
| 邏輯運算子 | OR |
滿足其中任一條件 |
| 邏輯運算子 | NOT |
條件不成立 |
| 特殊運算子 | BETWEEN |
在某一範圍內(包含邊界) |
| 特殊運算子 | LIKE |
模糊匹配字串模式(搭配 % 或 _) |
| 特殊運算子 | IN |
值在清單中的任一項 |
| 特殊運算子 | IS NULL / IS NOT NULL |
欄位值是否為 NULL |
假設有一個名為 Employees 的表格,包含 EmployeeID, LastName(姓氏), Salary(薪水)和 Department(部門)。
找出所有部門為 'Sales' 的員工:
SELECT EmployeeID, LastName
FROM Employees
WHERE Department = 'Sales';
找出薪水大於等於 50000 且部門不是 'HR' 的員工:
SELECT *
FROM Employees
WHERE Salary >= 50000 AND Department != 'HR';
找出薪水在 60000 到 80000 之間(包含 60000 和 80000)的員工:
SELECT *
FROM Employees
WHERE Salary BETWEEN 60000 AND 80000;
找出部門為 'Marketing' 或 'Finance' 的員工:
SELECT *
FROM Employees
WHERE Department IN ('Marketing', 'Finance');
這等同於使用 WHERE Department = 'Marketing' OR Department = 'Finance'。
SQL 的 GROUP BY 子句用於將 SELECT 陳述式中,具有相同值(或多個欄位的值組合)的行分組成彙總列。它經常與 SQL 的彙總函數一起使用,以便為每個群組計算出一個摘要值。
GROUP BY 的核心功能是將表格中具有相同值的多個單一行,合併成一個單獨的群組(Group)。COUNT()、SUM()、AVG()、MAX() 或 MIN() 等彙總函數結合,您可以計算出每個群組的統計摘要,而不是整個表格的摘要。GROUP BY 子句必須在 WHERE 子句之後,但在 HAVING 和 ORDER BY 子句之前。
SELECT column_name(s), aggregate_function(column_to_summarize)
FROM table_name
WHERE condition_on_rows -- (可選) 在分組前過濾單行
GROUP BY column_name(s) -- 指定用來分組的欄位
HAVING condition_on_groups -- (可選) 在分組後過濾群組
ORDER BY column_name(s);
重要規則: 任何出現在 SELECT 列表中,但沒有被彙總函數包圍的欄位,都必須包含在 GROUP BY 子句中。
假設有一個名為 Products 的表格,包含 Category(產品類別)和 Price(價格)。
SELECT Category, AVG(Price) AS AveragePrice, COUNT(ProductID) AS TotalProducts
FROM Products
GROUP BY Category;
GROUP BY Category:指令資料庫將所有具有相同 Category 值的行分組。AVG(Price):計算每個分組(每個類別)中所有產品價格的平均值。COUNT(ProductID):計算每個分組(每個類別)中的產品總數量。您可以根據多個欄位進行分組。只有當所有指定的欄位的值都相同時,這些行才會被分在同一個群組中。
SELECT Category, Supplier, SUM(SalesAmount) AS TotalSales
FROM SalesRecords
GROUP BY Category, Supplier
ORDER BY Category, Supplier;
這將產生一個結果,其中每一行代表一個獨特的「類別 + 供應商」組合的總銷售額。
| 函數 | 功能 |
|---|---|
COUNT() |
計算群組中的行數。 |
SUM() |
計算群組中數值欄位的總和。 |
AVG() |
計算群組中數值欄位的平均值。 |
MAX() |
找出群組中欄位的最大值。 |
MIN() |
找出群組中欄位的最小值。 |
在 SQL 中,HAVING 子句是用來過濾群組(Group)的結果,它通常與 GROUP BY 子句一起使用。
雖然 WHERE 子句用於過濾單個列的行(Rows),但在需要基於群組的摘要值(例如 COUNT(), SUM(), AVG() 等彙總函數的結果)來過濾群組時,就必須使用 HAVING 子句。
| 特徵 | WHERE 子句 | HAVING 子句 |
|---|---|---|
| 執行時機 | 在資料被分組(GROUP BY)之前,過濾原始的行。 | 在資料被分組(GROUP BY)之後,過濾彙總的群組。 |
| 可使用的條件 | 不能直接使用彙總函數(如 COUNT、SUM、AVG)。 | 必須使用彙總函數來設定過濾條件。 |
| 應用對象 | 單一的列值。 | 群組(Group)的結果。 |
SELECT column_name(s), aggregate_function(column_name)
FROM table_name
WHERE condition_on_rows -- (選擇性) 過濾單行
GROUP BY column_name(s)
HAVING condition_on_groups -- (必須) 過濾群組
ORDER BY column_name(s);
假設有一個名為 Orders 的表格,包含 CustomerID(客戶 ID)和 TotalAmount(訂單總金額)。我們想找出所有平均訂單金額超過 500 的客戶。
SELECT CustomerID, AVG(TotalAmount) AS AverageOrder
FROM Orders
GROUP BY CustomerID
HAVING AVG(TotalAmount) > 500;
GROUP BY CustomerID:將所有訂單按客戶 ID 分組。AVG(TotalAmount):計算每個客戶的平均訂單金額。HAVING AVG(TotalAmount) > 500:這是過濾條件。它告訴 SQL **只顯示那些平均訂單金額(即 AVG(TotalAmount) 的結果)大於 500 的群組(客戶)**。假設我們想找出所有訂單總數**大於等於 3** 並且平均訂單金額**小於 1000** 的客戶。
SELECT CustomerID, COUNT(OrderID) AS TotalOrders, AVG(TotalAmount) AS AverageOrder
FROM Orders
GROUP BY CustomerID
HAVING COUNT(OrderID) >= 3 AND AVG(TotalAmount) < 1000;
HAVING COUNT(OrderID) >= 3:過濾掉訂單總數少於 3 的客戶群組。AND AVG(TotalAmount) < 1000:同時過濾掉平均訂單金額大於或等於 1000 的客戶群組。在 SELECT 查詢中,如果定義了 expr1 AS field1,能否在 expr2 中使用 field1?
SQL 的執行順序決定了別名不能在同一個 SELECT 內部被再次引用:
SELECT price * 1.1 AS new_price, new_price + 10 AS final_price FROM products; -- 錯誤
Unknown column 'new_price' in 'field list'
可以在子查詢中先計算 new_price,然後在外部查詢中引用:
SELECT new_price, new_price + 10 AS final_price
FROM (SELECT price * 1.1 AS new_price FROM products) AS subquery;
若 SQL 支援 Common Table Expressions(CTE),可用 WITH 來簡化:
WITH cte AS (
SELECT price * 1.1 AS new_price FROM products
)
SELECT new_price, new_price + 10 AS final_price FROM cte;
如果只是簡單運算,可以直接重複計算(但不推薦,因為可讀性較差):
SELECT price * 1.1 AS new_price, price * 1.1 + 10 AS final_price FROM products;
SELECT 查詢內引用別名。WITH)來解決。JOIN 用於合併多個資料表的相關資料,根據某個欄位(通常是外鍵)建立關聯。
只返回兩個資料表中符合條件的資料。
SELECT orders.order_id, customers.name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id;
返回左表的所有資料,若右表沒有對應資料,則顯示 NULL。
SELECT customers.name, orders.order_id
FROM customers
LEFT JOIN orders ON customers.customer_id = orders.customer_id;
返回右表的所有資料,若左表沒有對應資料,則顯示 NULL。
SELECT customers.name, orders.order_id
FROM orders
RIGHT JOIN customers ON orders.customer_id = customers.customer_id;
返回左右兩表的所有資料,若沒有匹配則顯示 NULL。
MySQL 不支援 FULL JOIN,可用 LEFT JOIN 和 RIGHT JOIN 組合模擬。
SELECT customers.name, orders.order_id
FROM customers
LEFT JOIN orders ON customers.customer_id = orders.customer_id
UNION
SELECT customers.name, orders.order_id
FROM customers
RIGHT JOIN orders ON customers.customer_id = orders.customer_id;
返回兩個表的所有可能組合(笛卡兒積)。
SELECT customers.name, products.product_name
FROM customers
CROSS JOIN products;
用於同一個表內部的關聯,如員工的上級關係。
SELECT A.name AS employee, B.name AS manager
FROM employees A
JOIN employees B ON A.manager_id = B.employee_id;
-- abc.sql SOURCE other_file.sql; SOURCE another_file.sql;
-- abc.sql \i other_file.sql \i another_file.sql
#!/bin/bash mysql -u user -p database_name < abc.sql mysql -u user -p database_name < other_file.sql
cat abc.sql other_file.sql another_file.sql > combined.sql mysql -u user -p database_name < combined.sql
SET @param1 = 'value1'; SOURCE other_file.sql;2. 在 `other_file.sql` 中引用變數:
SELECT * FROM table WHERE column = @param1;
\set param1 'value1' \i other_file.sql2. 在 `other_file.sql` 中使用變數:
SELECT * FROM table WHERE column = :'param1';
sed "s/{param1}/value1/g" abc.sql | mysql -u user -p database_name
2. 在 SQL 文件中使用佔位符 `{param1}`,由命令列工具替換。
psql -d database_name -v param1=value1 -f abc.sql2. 在 SQL 文件中使用 `:'param1'` 表示變數。
Stored Procedure(預存常式 或 儲存程序)是一組預先編譯並存儲在資料庫中的 SQL 語句,可以透過呼叫執行,提高效率並減少重複代碼。
DELIMITER //
CREATE PROCEDURE GetAllProducts()
BEGIN
SELECT * FROM products;
END //
DELIMITER ;
CALL GetAllProducts();
查詢特定類別的商品:
DELIMITER //
CREATE PROCEDURE GetProductsByCategory(IN category_name VARCHAR(50))
BEGIN
SELECT * FROM products WHERE category = category_name;
END //
DELIMITER ;
呼叫:
CALL GetProductsByCategory('electronics');
計算某個類別的商品總數:
DELIMITER //
CREATE PROCEDURE GetProductCountByCategory(IN category_name VARCHAR(50), OUT total_count INT)
BEGIN
SELECT COUNT(*) INTO total_count FROM products WHERE category = category_name;
END //
DELIMITER ;
呼叫:
CALL GetProductCountByCategory('electronics', @count);
SELECT @count;
DELIMITER //
CREATE PROCEDURE CalculateTotalRevenue()
BEGIN
DECLARE total DECIMAL(10,2);
SELECT SUM(price) INTO total FROM sales;
SELECT total AS total_revenue;
END //
DELIMITER ;
呼叫:
CALL CalculateTotalRevenue();
DELIMITER //
CREATE PROCEDURE CheckStock(IN product_id INT, OUT stock_status VARCHAR(20))
BEGIN
DECLARE stock INT;
SELECT quantity INTO stock FROM inventory WHERE id = product_id;
IF stock > 10 THEN
SET stock_status = 'In Stock';
ELSEIF stock > 0 THEN
SET stock_status = 'Low Stock';
ELSE
SET stock_status = 'Out of Stock';
END IF;
END //
DELIMITER ;
呼叫:
CALL CheckStock(1, @status);
SELECT @status;
DELIMITER //
CREATE PROCEDURE CountDown(IN start_num INT)
BEGIN
DECLARE i INT;
SET i = start_num;
loop_label: LOOP
IF i <= 0 THEN
LEAVE loop_label;
END IF;
SELECT i;
SET i = i - 1;
END LOOP;
END //
DELIMITER ;
呼叫:
CALL CountDown(5);
DROP PROCEDURE IF EXISTS GetAllProducts;
DELIMITER 避免 SQL 語法衝突。在 MySQL 和 MariaDB 中,儲存程序的參數不能直接設定預設值(不像 SQL Server 或 PostgreSQL)。不過,可以使用 IF 條件語句來模擬預設值。
假設我們要查詢 users 表,當參數 user_id 沒有提供時,預設查詢 ID 為 1:
DELIMITER //
CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
IF user_id IS NULL THEN
SET user_id = 1; -- 預設值
END IF;
SELECT * FROM users WHERE id = user_id;
END //
DELIMITER ;
CALL GetUserById(NULL); -- 會查詢 id = 1
CALL GetUserById(5); -- 查詢 id = 5
COALESCE() 會在參數為 NULL 時回傳指定的預設值:
DELIMITER //
CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
SELECT * FROM users WHERE id = COALESCE(user_id, 1);
END //
DELIMITER ;
CALL GetUserById(NULL); -- 預設為 1
CALL GetUserById(10); -- 查詢 id = 10
如果想要參數可選,可以建立多個 Stored Procedure。例如:
DELIMITER //
CREATE PROCEDURE GetAllUsers()
BEGIN
SELECT * FROM users;
END //
CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
SELECT * FROM users WHERE id = user_id;
END //
DELIMITER ;
CALL GetAllUsers(); -- 無參數,查詢所有
CALL GetUserById(3); -- 查詢 id = 3
DEFAULT 值。IF 或 COALESCE() 模擬預設值。MySQL / MariaDB 的 Stored Procedure 不支援 RETURN 回傳查詢結果,但可以使用 OUT 參數來回傳值。
DELIMITER //
CREATE PROCEDURE GetUserCount(OUT user_count INT)
BEGIN
SELECT COUNT(*) INTO user_count FROM users;
END //
DELIMITER ;
CALL GetUserCount(@total);
SELECT @total; -- 顯示用戶數量
如果要回傳一個查詢結果,直接 SELECT 即可:
DELIMITER //
CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
SELECT * FROM users WHERE id = user_id;
END //
DELIMITER ;
CALL GetUserById(5); -- 查詢 ID 為 5 的用戶
雖然 MySQL 支援 RETURN,但只能回傳單一數值,通常用於控制流程:
DELIMITER //
CREATE PROCEDURE GetMaxSalary()
BEGIN
DECLARE max_salary DECIMAL(10,2);
SELECT MAX(salary) INTO max_salary FROM employees;
RETURN max_salary; -- 但這樣在 MySQL 不會直接返回值
END //
DELIMITER ;
CALL 來獲取 RETURN 值,因此建議使用 OUT 參數:DELIMITER //
CREATE PROCEDURE GetMaxSalary(OUT max_salary DECIMAL(10,2))
BEGIN
SELECT MAX(salary) INTO max_salary FROM employees;
END //
DELIMITER ;
CALL GetMaxSalary(@max);
SELECT @max; -- 顯示最高薪資
使用多個 OUT 參數回傳不同的計算結果:
DELIMITER //
CREATE PROCEDURE GetUserStats(OUT total_users INT, OUT avg_age DECIMAL(5,2))
BEGIN
SELECT COUNT(*) INTO total_users FROM users;
SELECT AVG(age) INTO avg_age FROM users;
END //
DELIMITER ;
CALL GetUserStats(@total, @avg);
SELECT @total, @avg; -- 顯示用戶總數與平均年齡
OUT 參數。SELECT。OUT 參數。RETURN 回傳查詢結果,只適用於流程控制。MySQL Stored Procedure 可以透過 OUT 參數回傳值,然後在 CALL 之外用 SELECT 取得該值。
DELIMITER //
CREATE PROCEDURE GetTotalUsers(OUT total_users INT)
BEGIN
SELECT COUNT(*) INTO total_users FROM users;
END //
DELIMITER ;
CALL GetTotalUsers(@total);
SELECT @total AS UserCount; -- 在 CALL 之外使用回傳值
如果 Stored Procedure 使用 SELECT 回傳結果,不能直接存入變數,但可以用 INSERT INTO ... SELECT。
DELIMITER //
CREATE PROCEDURE GetMaxSalary()
BEGIN
SELECT MAX(salary) AS max_salary FROM employees;
END //
DELIMITER ;
CREATE TEMPORARY TABLE temp_result (max_salary DECIMAL(10,2));
INSERT INTO temp_result EXECUTE GetMaxSalary();
SELECT max_salary FROM temp_result; -- 在 CALL 之外使用
如果 Stored Procedure 產生的結果需要在變數中存取,可以使用 PREPARE 和 EXECUTE。
DELIMITER //
CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
SELECT name FROM users WHERE id = user_id;
END //
DELIMITER ;
SET @sql = 'CALL GetUserById(5)';
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
OUT 參數回傳單一值,透過 @變數 存取。INSERT INTO ... CALL 存入暫存表。PREPARE 和 EXECUTE。在 MySQL / MariaDB 中,Stored Function(函數)不能回傳 SELECT 結果集,否則會出現錯誤:
ERROR 1415 (0A000): Not allowed to return a result set from a function
函數不能回傳結果集,但 Stored Procedure 可以。
DELIMITER //
CREATE FUNCTION GetUsers()
RETURNS TABLE
BEGIN
RETURN (SELECT * FROM users); -- 這是不允許的
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE GetUsers()
BEGIN
SELECT * FROM users;
END //
DELIMITER ;
CALL GetUsers();
如果只需要回傳單一值(如計數或最大值),可以用 RETURN。
DELIMITER //
CREATE FUNCTION GetUserCount()
RETURNS INT DETERMINISTIC
BEGIN
DECLARE total INT;
SELECT COUNT(*) INTO total FROM users;
RETURN total;
END //
DELIMITER ;
SELECT GetUserCount();
如果真的需要在函數內回傳多行結果,可以讓函數插入資料到 Temporary Table,然後在外部查詢。
DELIMITER //
CREATE FUNCTION PopulateTempUsers()
RETURNS INT DETERMINISTIC
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS temp_users AS (SELECT * FROM users);
RETURN 1;
END //
DELIMITER ;
SELECT PopulateTempUsers();
SELECT * FROM temp_users;
RETURN。HeidiSQL 是一款免費的開源 SQL 客戶端,支援 MySQL、MariaDB、PostgreSQL 和 MS SQL Server,提供 GUI 來管理資料庫、執行 SQL 查詢、匯入/匯出資料等。
1. 前往官方網站下載 HeidiSQL: https://www.heidisql.com/download.php
2. 執行安裝程式並按照指示完成安裝
3. 開啟 HeidiSQL,設定新連線
1. 開啟 HeidiSQL
2. 點擊「新增」建立新連線
3. 設定:
- 主機名/IP:127.0.0.1 或 遠端伺服器 IP
- 使用者名稱:root 或其他使用者
- 密碼:對應的密碼
- 連接埠:3306(MySQL / MariaDB)
4. 點擊「開啟」連接資料庫
在 HeidiSQL 查詢視窗中輸入 SQL 語句:
SELECT * FROM users WHERE status = 'active';
點擊「執行」按鈕,即可查看結果。
1. 右鍵點擊資料庫 → 選擇「匯出 SQL」
2. 選擇要匯出的資料表
3. 設定匯出格式(.sql、.csv、.json)
4. 點擊「匯出」
1. 打開 HeidiSQL,選擇目標資料庫
2. 點擊「工具」→「執行 SQL 檔案」
3. 選擇 .sql 檔案並執行
1. 進入「工具」→「管理使用者權限」
2. 選擇要管理的使用者
3. 設定資料庫權限(SELECT、INSERT、UPDATE、DELETE 等)
4. 點擊「儲存」
1. 開啟 HeidiSQL。
2. 連接 MySQL 或 MariaDB 伺服器。
3. 在左側的「資料庫」列表中選擇目標資料庫。
1. 在左側的資料庫名稱上點擊右鍵,選擇「建立新的」→「儲存程序」。
2. HeidiSQL 會打開一個新的 SQL 編輯視窗,並提供預設的儲存程序模板。
以下是一個簡單的範例,返回 users 表中的所有資料:
DELIMITER //
CREATE PROCEDURE GetAllUsers()
BEGIN
SELECT * FROM users;
END //
DELIMITER ;
1. 點擊「執行」按鈕(綠色閃電)。
2. 若執行成功,可在左側的「儲存程序」欄位中找到該程序。
CALL GetAllUsers();
傳入參數來篩選數據,例如根據用戶 ID 查詢:
DELIMITER //
CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
SELECT * FROM users WHERE id = user_id;
END //
DELIMITER ;
呼叫帶參數的儲存程序:
CALL GetUserById(1);
DROP PROCEDURE IF EXISTS GetAllUsers;
DELIMITER 確保語法正確。CALL 測試儲存程序。email: [email protected]