最近看到一個不錯的 SQL 編程風格指南:https://www.sqlstyle.guide/zh/僅供參考,最重要的是選擇一套方針并嚴格遵守它。一般原則應該做的事情使用一致的、描述性的名稱。合理地使用空格和縮進來增強可讀...
最近看到一個不錯的 SQL 編程風格指南:https://www.sqlstyle.guide/zh/
僅供參考,最重要的是選擇一套方針并嚴格遵守它。
一般原則
應該做的事情
使用一致的、描述性的名稱。
合理地使用空格和縮進來增強可讀性。
存儲符合 ISO-8601 標準的日期格式(YYYY-MM-DDTHH:MM:SS.SSSSS)。
為了提高可移植性,最好僅使用標準 SQL 函數而不是特定供應商的函數。
保證代碼簡潔明了、沒有多余的 SQL —— 比如非必要的引號或括號,或者可以推導出的 WHERE 子句。
必要時在 SQL 代碼中加入注釋。優先使用 C 語言式的以 /* 開始以 */ 結束的塊注釋,或使用以 -- 開始的行注釋,并在末尾換行。
SELECT file_hash -- stored ssdeep hash FROM file_system WHERE file_name = '.vimrc';
/* Updating the file record after writing to the file */ UPDATE file_system SET file_modified_date = '1980-02-22 13:19:01.00000', file_size = 209732 WHERE file_name = '.vimrc';
應避免的事情
駝峰命名法 —— 它不適合快速掃讀。
描述性的前綴或匈牙利命名法比如 sp_ 或 tbl。
復數形式 —— 盡量使用更自然的集合術語。比如,用“staff”替代“employees”,或用“people”替代“individuals”。
被引號包裹的標識符(quoted identifier)—— 如果你必須使用這樣的標識符,最好堅持用 SQL92 的雙引號來提高可移植性(你可能需要配置你的 SQL 服務器以支持此特性,具體取決于供應商)。
面向對象編程的原則不該應用到 SQL 或數據庫結構上。
命名慣例
一般原則
保證名字獨一無二且不是保留字。
保證名字長度不超過 30 個字節 —— 實際上,如果你不使用多字節字符集,就是 30 個字符。
名字要以字母開頭,不能以下劃線結尾。
只在名字中使用字母、數字和下劃線。
不要在名字中出現連續下劃線 —— 這樣很難辨認。
在名字中需要空格的地方用下劃線代替(first name 變為 first_name)。
盡量避免使用縮寫詞。使用時一定確定這個縮寫簡明易懂。
SELECT first_name
FROM staff;
表名
使用集合名稱,或在不那么理想的情況下使用復數形式。如 staff(建議使用)和 employees。
不要使用類似 tbl 或其他的描述性的前綴或匈牙利命名法。
表不應該同它的列同名,反之亦然。
盡量避免連接兩個表的名字作為關系表(relationship table)的名字。與其使用 cars_mechanics 做表名不如使用 services。
列名
總是使用單數形式。
避免直接使用 id 做表的主標識符。
避免列名和表名同名,反之亦然。
總是使用小寫字母,除非是特殊情況,如專有名詞。
別名與關聯名
別名應該與它們所指的對象或表達式相關聯。
一般來說,關聯名應該由對象名中每一個單詞的首字母組成。
如果已經有相同的關聯名了,那么在關聯名后加一個數字。
總是加上 AS 關鍵字,因為這樣的明確聲明易于閱讀。
為計算出的數據(SUM() 或 AVG())命名時,用一個將這條數據存在表中時會使用的列名。
SELECT first_name AS fn
FROM staff AS s1
JOIN students AS s2
ON s2.mentor_id = s1.staff_num;
SELECT SUM(s.monitor_tally) AS monitor_total
FROM staff AS s;
存儲過程名
名字一定要包含動詞。
不要附加 sp_ 或任何其他這樣的描述性的前綴或使用匈牙利表示法。
統一的后綴
下列后綴有統一的意義,能保證 SQL 代碼更容易理解。在合適的時候使用正確的后綴。
_id —— 獨一無二的標識符,如主鍵。
_status —— 標志值或任何表示狀態的值,比如 publication_status。
_total —— 總和或某些值的和。
_num —— 表示該字段包含數值。
_name —— 表示名字,例如 first_name。
_seq —— 包含一系列值。
_date —— 表示該列包含日期。
_tally —— 計數值。
_size —— 大小,如文件大小或服裝大小。
_addr —— 地址,有形的或無形的,如 ip_addr
查詢語句
保留字
關鍵字總是大寫,如 SELECT 和 WHERE。
最好使用關鍵字的全稱而不是簡寫,用 ABSOLUTE 而不用 ABS。
當標準 ANSI SQL 關鍵字能完成相同的事情時,不要使用數據庫服務器特定的關鍵字,這樣能增強可移植性。
SELECT model_num
FROM phones AS p
WHERE p.release_date > '2014-09-30';
空白字符
正確地使用空白字符對清晰的代碼十分重要。不要把代碼堆在一起或移除自然語言中的空格。
空格
用空格使根關鍵字都結束在同一列上。在代碼中間形成一個從上到下的“川流”,這樣幫助讀者快速掃視代碼并將關鍵字和實現細節分開。川流在排版時應該避免,但是對閱讀 SQL 語句是有幫助的。
(SELECT f.species_name,
AVG(f.height) AS average_height, AVG(f.diameter) AS average_diameter
FROM flora AS f
WHERE f.species_name = 'Banksia'
OR f.species_name = 'Sheoak'
OR f.species_name = 'Wattle'
GROUP BY f.species_name, f.observation_date)
UNION ALL
(SELECT b.species_name,
AVG(b.height) AS average_height, AVG(b.diameter) AS average_diameter
FROM botanic_garden_flora AS b
WHERE b.species_name = 'Banksia'
OR b.species_name = 'Sheoak'
OR b.species_name = 'Wattle'
GROUP BY b.species_name, b.observation_date);
注意 SELECT 和 FROM 等關鍵字,都右對齊,而實際的列名和實現細節都左對齊。
注意下列情況總是加入空格:
在等號(=)前后
在逗號(,)后
成對的單引號(')前后,除非在括號中或后面是逗號 / 分號
SELECT a.title, a.release_date, a.recording_date
FROM albums AS a
WHERE a.title = 'Charcoal Lane'
OR a.title = 'The New Danger';
換行
總是換行的情況:
在 AND 或 OR 前
在分號后(分隔語句以提高可讀性)
在每個關鍵字定義之后
將多個列組成一個邏輯組時的逗號后
將代碼分隔成相關聯的多個部分,幫助提高大段代碼的可讀性
讓所有的關鍵字右對齊、所有的值左對齊,這樣就能在查詢語句中間留出一個空隙,有助于快速掃讀整個查詢的定義。
INSERT INTO albums (title, release_date, recording_date)
VALUES ('Charcoal Lane', '1990-01-01 01:01:01.00000', '1990-01-01 01:01:01.00000'),
('The New Danger', '2008-01-01 01:01:01.00000', '1990-01-01 01:01:01.00000');
UPDATE albums
SET release_date = '1990-01-01 01:01:01.00000'
WHERE title = 'The New Danger';
SELECT a.title,
a.release_date, a.recording_date, a.production_date -- 將所有的日期放在一起
FROM albums AS a
WHERE a.title = 'Charcoal Lane'
OR a.title = 'The New Danger';
縮進
為確保 SQL 的可讀性,一定要遵守下列規則。
Join 語句
Join 語句應該縮進到川流的另一側并在必要的時候添加一個換行。
SELECT r.last_name
FROM riders AS r
INNER JOIN bikes AS b
ON r.bike_vin_num = b.vin_num
AND b.engine_tally > 2
INNER JOIN crew AS c
ON r.crew_chief_last_name = c.last_name
AND c.chief = 'Y';
子查詢
子查詢應該在川流的右側對齊并使用其他查詢相同的樣式。有時候將右括號單獨置于一行并同與它配對的左括號對齊是有意義的 —— 尤其是當存在嵌套子查詢的時候。
SELECT r.last_name,
(SELECT MAX(YEAR(championship_date))
FROM champions AS c
WHERE c.last_name = r.last_name
AND c.confirmed = 'Y') AS last_championship_year
FROM riders AS r
WHERE r.last_name IN
(SELECT c.last_name
FROM champions AS c
WHERE YEAR(championship_date) > '2008'
AND c.confirmed = 'Y');
推薦的形式
盡量使用 BETWEEN 而不是多個 AND 語句。
同樣地,使用 IN() 而不是多個 OR 語句。
當數據輸出數據庫時需要處理時,使用 CASE 表達式。CASE 語句能嵌套形成更復雜的邏輯結構。
盡量避免 UNION 語句和臨時表。如果數據庫架構能夠不靠這些語句運行,那么多數情況下它就不應該依靠這些語句。
SELECT CASE postcode
WHEN 'BN1' THEN 'Brighton'
WHEN 'EH1' THEN 'Edinburgh'
END AS city
FROM office_locations
WHERE country = 'United Kingdom'
AND opening_time BETWEEN 8 AND 9
AND postcode IN ('EH1', 'BN1', 'NN1', 'KW1');
創建語句
聲明模式信息時維護可讀代碼也很重要。所以列定義的順序和分組一定要有意義。
在 CREATE 定義中,每個列定義要縮進 4 個空格。
選擇數據類型
盡量不使用供應商相關的數據類型 —— 這些類型不可移植甚至有可能不能在相同供應商的舊版本系統上使用。
只在真的需要浮點數運算的時候才使用 REAL 和 FLOAT 類型,否則使用 NUMERIC 和 DECIMAL 類型。浮點數舍入誤差是個麻煩。
指定默認類型
默認值一定與列的類型相同 —— 如果一個列的類型是 DECIMAL 那么就不要使用 INTEGER 類型的值作為默認值。
默認值要緊跟類型聲明并在 NOT NULL 聲明前。
約束和鍵
約束和鍵是構成數據庫系統的重要組成部分。它們能很快地變得難以閱讀和理解,所以遵從指導方針是很重要的。
選擇鍵
設計時應該謹慎選擇構成鍵的列,因為鍵會影響性能和數據完整性。
鍵在某種程度上應該是獨一無二的。
該值在不同表中的類型應該相同并且盡量不會更改。
該值能否通過某種標準格式(如 ISO 發布的標準)?鼓勵與前面第二點一致。
盡量讓鍵保持簡單,但在適當情況下不要害怕使用復合鍵。
以上是定義數據庫時合乎邏輯的平衡做法。當需求變更時,鍵也應該根據情況更新。
定義約束
確定鍵后,就可以用約束和字值段驗證來定義它們。
概述
表至少需要一個鍵來保證其完整性和可用性。
除了 UNIQUE 、PRIMARY KEY 和 FOREIGN KEY 之外(數據庫供應商會提供相應的檢查),約束應該有名字。
布局和順序
在 CREATE TABLE 語句后先定義主鍵。
約束的定義應該緊跟它相應的列的定義后。
如果該約束與多個列相關,那么讓它離相關的列越近越好。實在不行就將它放在表定義的最后。
如果是應用于整個表的表級別的約束,那么就將它放在表定義的最后。
按照字母順序安排定義,ON DELETE 排在 ON UPDATE 前。
有道理的話,把所有相關的語句對齊。比如,把所有 NOT NULL 定義對齊到同一列。這樣做并不難,但是能提高可讀性。
校驗
當字符串的格式已知時,用 LIKE 和 SIMILAR TO 約束來保證它們的完整性。
當數值的范圍可以確定時,用范圍 CHECK() 來防止錯誤的值進入數據庫或在沒有提示的情況下截斷。大部分情況下至少要確認數值大于零。
CHECK() 約束應該在單獨的子句中以便 debug。
示例
CREATE TABLE staff (
PRIMARY KEY (staff_num),
staff_num INT(5) NOT NULL,
first_name VARCHAR(100) NOT NULL,
pens_in_drawer INT(2) NOT NULL,
CONSTRAINT pens_in_drawer_range
CHECK(pens_in_drawer BETWEEN 1 AND 99)
);
應該避免的設計
在關系型數據庫的設計中應用面向對象設計思想(原則)—— 面向對象設計思想(原則)并不能很好地適用于關系型數據庫的設計,避免這個陷阱。
將值存入一列并將其單位存在另一列 —— 列的定義應該讓自己的單位不言自明以避免在應用內進行合并。使用 CHECK() 來保證插入的數據是合法的。
EAV (Entity Attribute Value) 表 —— 應該用專門的產品來處理這樣的無模式數據。
因為某些原因(如為了根據時間歸檔、為了劃分跨國組織的區域)將本應該放在一個表中的數據分到多個表中 —— 這樣的設計導致以后必須使用 UNION 操作而不能直接查詢一個表。
附錄
列的數據類型
出于在數據庫引擎之間達到最大程度兼容的目的,下面是一些建議使用的列數據類型。
字符型
CHAR
CLOB
VARCHAR
數值型
精確數值類型
BIGINT
DECIMAL
DECFLOAT
INTEGER
NUMERIC
SMALLINT
近似數值類型
DOUBLE PRECISION
FLOAT
REAL
日期時間類型
DATE
TIME
TIMESTAMP
二進制類型
BINARY
BLOB
VARBINARY
其他類型
Boolean
INTERVAL
XML
原文來源:https://mp.weixin.qq.com/s/XOfjELbnQWDUdj1Tg3mndQ
來源:本文內容搜集或轉自各大網絡平臺,并已注明來源、出處,如果轉載侵犯您的版權或非授權發布,請聯系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內容的準確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負責,僅作分享之用,文章版權及插圖屬于原作者。
Copyright?2013-2024 JSedu114 All Rights Reserved. 江蘇教育信息綜合發布查詢平臺保留所有權利
蘇公網安備32010402000125
蘇ICP備14051488號-3技術支持:南京博盛藍睿網絡科技有限公司
南京思必達教育科技有限公司版權所有 百度統計