最近看到一個不錯的 SQL 編程風格指南:https://www.sqlstyle.guide/zh/僅供參考,最重要的是選擇一套方針并嚴格遵守它。一般原則應該做的事情使用一致的、描述性的名稱。合理地使用空格和縮進來增強可讀...
最近看到一個不錯的 SQL 編程風格指南:https://www.sqlstyle.guide/zh/
僅供參考,最重要的是選擇一套方針并嚴格遵守它。
一般原則
應該做的事情
使用一致的、描述性的名稱。
合理地使用空格和縮進來增強可讀性。
存儲符合 ISO-8601 標準的日期格式(YYYY-MM-DDTHH:MM:SS.SSSSS)。
為了提高可移植性,最好僅使用標準 SQL 函數(shù)而不是特定供應商的函數(shù)。
保證代碼簡潔明了、沒有多余的 SQL —— 比如非必要的引號或括號,或者可以推導出的 WHERE 子句。
必要時在 SQL 代碼中加入注釋。優(yōu)先使用 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。
復數(shù)形式 —— 盡量使用更自然的集合術語。比如,用“staff”替代“employees”,或用“people”替代“individuals”。
被引號包裹的標識符(quoted identifier)—— 如果你必須使用這樣的標識符,最好堅持用 SQL92 的雙引號來提高可移植性(你可能需要配置你的 SQL 服務器以支持此特性,具體取決于供應商)。
面向?qū)ο缶幊痰脑瓌t不該應用到 SQL 或數(shù)據(jù)庫結構上。
命名慣例
一般原則
保證名字獨一無二且不是保留字。
保證名字長度不超過 30 個字節(jié) —— 實際上,如果你不使用多字節(jié)字符集,就是 30 個字符。
名字要以字母開頭,不能以下劃線結尾。
只在名字中使用字母、數(shù)字和下劃線。
不要在名字中出現(xiàn)連續(xù)下劃線 —— 這樣很難辨認。
在名字中需要空格的地方用下劃線代替(first name 變?yōu)?nbsp;first_name)。
盡量避免使用縮寫詞。使用時一定確定這個縮寫簡明易懂。
SELECT first_name
FROM staff;
表名
使用集合名稱,或在不那么理想的情況下使用復數(shù)形式。如 staff(建議使用)和 employees。
不要使用類似 tbl 或其他的描述性的前綴或匈牙利命名法。
表不應該同它的列同名,反之亦然。
盡量避免連接兩個表的名字作為關系表(relationship table)的名字。與其使用 cars_mechanics 做表名不如使用 services。
列名
總是使用單數(shù)形式。
避免直接使用 id 做表的主標識符。
避免列名和表名同名,反之亦然。
總是使用小寫字母,除非是特殊情況,如專有名詞。
別名與關聯(lián)名
別名應該與它們所指的對象或表達式相關聯(lián)。
一般來說,關聯(lián)名應該由對象名中每一個單詞的首字母組成。
如果已經(jīng)有相同的關聯(lián)名了,那么在關聯(lián)名后加一個數(shù)字。
總是加上 AS 關鍵字,因為這樣的明確聲明易于閱讀。
為計算出的數(shù)據(jù)(SUM() 或 AVG())命名時,用一個將這條數(shù)據(jù)存在表中時會使用的列名。
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_ 或任何其他這樣的描述性的前綴或使用匈牙利表示法。
統(tǒng)一的后綴
下列后綴有統(tǒng)一的意義,能保證 SQL 代碼更容易理解。在合適的時候使用正確的后綴。
_id —— 獨一無二的標識符,如主鍵。
_status —— 標志值或任何表示狀態(tài)的值,比如 publication_status。
_total —— 總和或某些值的和。
_num —— 表示該字段包含數(shù)值。
_name —— 表示名字,例如 first_name。
_seq —— 包含一系列值。
_date —— 表示該列包含日期。
_tally —— 計數(shù)值。
_size —— 大小,如文件大小或服裝大小。
_addr —— 地址,有形的或無形的,如 ip_addr
查詢語句
保留字
關鍵字總是大寫,如 SELECT 和 WHERE。
最好使用關鍵字的全稱而不是簡寫,用 ABSOLUTE 而不用 ABS。
當標準 ANSI SQL 關鍵字能完成相同的事情時,不要使用數(shù)據(jù)庫服務器特定的關鍵字,這樣能增強可移植性。
SELECT model_num
FROM phones AS p
WHERE p.release_date > '2014-09-30';
空白字符
正確地使用空白字符對清晰的代碼十分重要。不要把代碼堆在一起或移除自然語言中的空格。
空格
用空格使根關鍵字都結束在同一列上。在代碼中間形成一個從上到下的“川流”,這樣幫助讀者快速掃視代碼并將關鍵字和實現(xiàn)細節(jié)分開。川流在排版時應該避免,但是對閱讀 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 等關鍵字,都右對齊,而實際的列名和實現(xiàn)細節(jié)都左對齊。
注意下列情況總是加入空格:
在等號(=)前后
在逗號(,)后
成對的單引號(')前后,除非在括號中或后面是逗號 / 分號
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 前
在分號后(分隔語句以提高可讀性)
在每個關鍵字定義之后
將多個列組成一個邏輯組時的逗號后
將代碼分隔成相關聯(lián)的多個部分,幫助提高大段代碼的可讀性
讓所有的關鍵字右對齊、所有的值左對齊,這樣就能在查詢語句中間留出一個空隙,有助于快速掃讀整個查詢的定義。
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 的可讀性,一定要遵守下列規(guī)則。
Join 語句
Join 語句應該縮進到川流的另一側(cè)并在必要的時候添加一個換行。
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';
子查詢
子查詢應該在川流的右側(cè)對齊并使用其他查詢相同的樣式。有時候?qū)⒂依ㄌ枂为氈糜谝恍胁⑼c它配對的左括號對齊是有意義的 —— 尤其是當存在嵌套子查詢的時候。
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 語句。
當數(shù)據(jù)輸出數(shù)據(jù)庫時需要處理時,使用 CASE 表達式。CASE 語句能嵌套形成更復雜的邏輯結構。
盡量避免 UNION 語句和臨時表。如果數(shù)據(jù)庫架構能夠不靠這些語句運行,那么多數(shù)情況下它就不應該依靠這些語句。
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');
創(chuàng)建語句
聲明模式信息時維護可讀代碼也很重要。所以列定義的順序和分組一定要有意義。
在 CREATE 定義中,每個列定義要縮進 4 個空格。
選擇數(shù)據(jù)類型
盡量不使用供應商相關的數(shù)據(jù)類型 —— 這些類型不可移植甚至有可能不能在相同供應商的舊版本系統(tǒng)上使用。
只在真的需要浮點數(shù)運算的時候才使用 REAL 和 FLOAT 類型,否則使用 NUMERIC 和 DECIMAL 類型。浮點數(shù)舍入誤差是個麻煩。
指定默認類型
默認值一定與列的類型相同 —— 如果一個列的類型是 DECIMAL 那么就不要使用 INTEGER 類型的值作為默認值。
默認值要緊跟類型聲明并在 NOT NULL 聲明前。
約束和鍵
約束和鍵是構成數(shù)據(jù)庫系統(tǒng)的重要組成部分。它們能很快地變得難以閱讀和理解,所以遵從指導方針是很重要的。
選擇鍵
設計時應該謹慎選擇構成鍵的列,因為鍵會影響性能和數(shù)據(jù)完整性。
鍵在某種程度上應該是獨一無二的。
該值在不同表中的類型應該相同并且盡量不會更改。
該值能否通過某種標準格式(如 ISO 發(fā)布的標準)?鼓勵與前面第二點一致。
盡量讓鍵保持簡單,但在適當情況下不要害怕使用復合鍵。
以上是定義數(shù)據(jù)庫時合乎邏輯的平衡做法。當需求變更時,鍵也應該根據(jù)情況更新。
定義約束
確定鍵后,就可以用約束和字值段驗證來定義它們。
概述
表至少需要一個鍵來保證其完整性和可用性。
除了 UNIQUE 、PRIMARY KEY 和 FOREIGN KEY 之外(數(shù)據(jù)庫供應商會提供相應的檢查),約束應該有名字。
布局和順序
在 CREATE TABLE 語句后先定義主鍵。
約束的定義應該緊跟它相應的列的定義后。
如果該約束與多個列相關,那么讓它離相關的列越近越好。實在不行就將它放在表定義的最后。
如果是應用于整個表的表級別的約束,那么就將它放在表定義的最后。
按照字母順序安排定義,ON DELETE 排在 ON UPDATE 前。
有道理的話,把所有相關的語句對齊。比如,把所有 NOT NULL 定義對齊到同一列。這樣做并不難,但是能提高可讀性。
校驗
當字符串的格式已知時,用 LIKE 和 SIMILAR TO 約束來保證它們的完整性。
當數(shù)值的范圍可以確定時,用范圍 CHECK() 來防止錯誤的值進入數(shù)據(jù)庫或在沒有提示的情況下截斷。大部分情況下至少要確認數(shù)值大于零。
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)
);
應該避免的設計
在關系型數(shù)據(jù)庫的設計中應用面向?qū)ο笤O計思想(原則)—— 面向?qū)ο笤O計思想(原則)并不能很好地適用于關系型數(shù)據(jù)庫的設計,避免這個陷阱。
將值存入一列并將其單位存在另一列 —— 列的定義應該讓自己的單位不言自明以避免在應用內(nèi)進行合并。使用 CHECK() 來保證插入的數(shù)據(jù)是合法的。
EAV (Entity Attribute Value) 表 —— 應該用專門的產(chǎn)品來處理這樣的無模式數(shù)據(jù)。
因為某些原因(如為了根據(jù)時間歸檔、為了劃分跨國組織的區(qū)域)將本應該放在一個表中的數(shù)據(jù)分到多個表中 —— 這樣的設計導致以后必須使用 UNION 操作而不能直接查詢一個表。
附錄
列的數(shù)據(jù)類型
出于在數(shù)據(jù)庫引擎之間達到最大程度兼容的目的,下面是一些建議使用的列數(shù)據(jù)類型。
字符型
CHAR
CLOB
VARCHAR
數(shù)值型
精確數(shù)值類型
BIGINT
DECIMAL
DECFLOAT
INTEGER
NUMERIC
SMALLINT
近似數(shù)值類型
DOUBLE PRECISION
FLOAT
REAL
日期時間類型
DATE
TIME
TIMESTAMP
二進制類型
BINARY
BLOB
VARBINARY
其他類型
Boolean
INTERVAL
XML
原文來源:https://mp.weixin.qq.com/s/XOfjELbnQWDUdj1Tg3mndQ
來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡平臺,并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權或非授權發(fā)布,請聯(lián)系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內(nèi)容的準確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負責,僅作分享之用,文章版權及插圖屬于原作者。
Copyright?2013-2024 JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺保留所有權利
蘇公網(wǎng)安備32010402000125
蘇ICP備14051488號-3技術支持:南京博盛藍睿網(wǎng)絡科技有限公司