1
0
Fork 0
mirror of https://github.com/treffynnon/sqlstyle.guide.git synced 2025-03-09 12:49:51 -05:00

Inital updates

This is the inital pass of updating the style guide
This commit is contained in:
Ryan Howe 2018-03-16 10:48:11 -04:00
parent 0ce5e1ff85
commit 896ea5538e

View file

@ -51,117 +51,73 @@ UPDATE file_system
### Avoid ### Avoid
* CamelCase—it is difficult to scan quickly.
* Descriptive prefixes or Hungarian notation such as `sp_` or `tbl`.
* Plurals—use the more natural collective term where possible instead. For example * Plurals—use the more natural collective term where possible instead. For example
`staff` instead of `employees` or `people` instead of `individuals`. `staff` instead of `employees` or `people` instead of `individuals`.
* Quoted identifiers—if you must use them then stick to SQL92 double quotes for
portability (you may need to configure your SQL server to support this depending
on vendor).
* Object oriented design principles should not be applied to SQL or database * Object oriented design principles should not be applied to SQL or database
structures. structures.
## Naming conventions ## Naming conventions
### General ### All Naming Conventions
* See Confluence documentation for [Ives Database Design Guide][design-guide]
* Ensure the name is unique and does not exist as a
[reserved keyword][reserved-keywords].
* Keep the length to a maximum of 30 bytes—in practice this is 30 characters
unless you are using multi-byte character set.
* Names must begin with a letter and may not end with an underscore.
* Only use letters, numbers and underscores in names.
* Avoid the use of multiple consecutive underscores—these can be hard to read.
* Use underscores where you would naturally include a space in the name (first
name becomes `first_name`).
* Avoid abbreviations and if you have to use them make sure they are commonly
understood.
```sql
SELECT first_name
FROM staff;
```
### Tables
* Use a collective name or, less ideally, a plural form. For example (in order of
preference) `staff` and `employees`.
* Do not prefix with `tbl` or any other such descriptive prefix or Hungarian
notation.
* Never give a table the same name as one of its columns and vice versa.
* Avoid, where possible, concatenating two table names together to create the name
of a relationship table. Rather than `cars_mechanics` prefer `services`.
### Columns
* Always use the singular name.
* Where possible avoid simply using `id` as the primary identifier for the table.
* Do not add a column with the same name as its table and vice versa.
* Always use lowercase except where it may make sense not to such as proper nouns.
### Aliasing or correlations ### Aliasing or correlations
#### Aliasing Column Names
* Avoid unnessisary aliases at all times
* Must always alias `COUNT(*)` columns
* Must always alias computed data (`SUM()` or `AVG()` or `IF()`) use the name you would give it were it a column defined in the schema.
* Must always include the `AS` keyword, which makes it easier to read as it is explicit.
* Should relate in some way to the object or expression they are aliasing. * Should relate in some way to the object or expression they are aliasing.
* As a rule of thumb the correlation name should be the first letter of each word
in the object's name. #### Aliasing Table Names
* If there is already a correlation with the same name then append a number. * All Tables must be aliased when using more than one in a JOIN
* Always include the `AS` keyword—makes it easier to read as it is explicit. * Table aliases will be made up of the first letter of every word in the table name unless
* For computed data (`SUM()` or `AVG()`) use the name you would give it were it * unless the alias is a reseverd word ie. `FROM INTERNATIONAL_FILINGS AS IF` will cause an error in SQL
a column defined in the schema. * in this case us an abbreviated name for the table ie. `FROM INTERNATIONAL_FILINGS AS IFILINGS`
* if the aliases for two table will be the same, or the same table is used more then once, append a number in order of apperance in the query
* When a query contains multiple databases the first letter of the database, in lower case will be prepended to the table alias ie. `FROM international.ENTITY_MAP AS iEM INNER JOIN secdocs.COMPANY AS sC`
```sql ```sql
SELECT first_name AS fn SELECT
FROM staff AS s1 COUNT(*) as student_staff_count
JOIN students AS s2 FROM
ON s2.mentor_id = s1.staff_num; STAFF AS S1
INNER JOIN
STUDENTS AS S2
ON S2.mentor_id = S1.staff_num;
``` ```
```sql ```sql
SELECT SUM(s.monitor_tally) AS monitor_total SELECT
FROM staff AS s; SUM(s.monitor_tally) AS monitor_total
FROM
STAFF AS S
GROUP BY
S.staff_department_fkey;
``` ```
### Stored procedures
* The name must contain a verb.
* Do not prefix with `sp_` or any other such descriptive prefix or Hungarian
notation.
### Uniform suffixes ### Uniform suffixes
The following suffixes have a universal meaning ensuring the columns can be read The following suffixes have a universal meaning ensuring the columns can be read
and understood easily from SQL code. Use the correct suffix where appropriate. and understood easily from SQL code. Use the correct suffix where appropriate.
* `_id`—a unique identifier such as a column that is a primary key. * `_key`—a unique identifier such as a column that is a primary key.
* `_status`—flag value or some other status of any type such as * `_status`—flag value or some other status of any type such as `publication_status`.
`publication_status`.
* `_total`—the total or sum of a collection of values. * `_total`—the total or sum of a collection of values.
* `_num`—denotes the field contains any kind of number. * `_num`—denotes the field contains any kind of number.
* `_name`—signifies a name such as `first_name`. * `_name`—signifies a name such as `first_name`.
* `_seq`—contains a contiguous sequence of values.
* `_date`—denotes a column that contains the date of something. * `_date`—denotes a column that contains the date of something.
* `_tally`—a count. * `_count`—a count.
* `_size`—the size of something such as a file size or clothing. * `_size`—the size of something such as a file size or clothing.
* `_addr`—an address for the record could be physical or intangible such as * `_addr`—an address for the record could be physical or intangible such as `ip_addr`.
`ip_addr`.
## Query syntax ## Query syntax
### Reserved words ### Reserved words
Always use uppercase for the [reserved keywords][reserved-keywords] Always use uppercase for the [reserved keywords][reserved-keywords] like `SELECT`, `WHERE` or `IF`.
like `SELECT` and `WHERE`.
It is best to avoid the abbreviated keywords and use the full length ones where Data manipulation statements should have every clause keyword on a line of its own unless performing extremely simple statements. Examples of the clause keywords are `SELECT`, `DELETE`, `UPDATE`, `FROM`, `WHERE`, `HAVING`, `GROUP BY`, `ORDER BY`, `LIMIT`. An example of a simple single line statements `SELECT COUNT(*) as student_count FROM STUDENTS WHERE graduated = 0;`
available (prefer `ABSOLUTE` to `ABS`).
Do not use database server specific keywords where an ANSI SQL keyword already
exists performing the same function. This helps to make code more portable.
```sql
SELECT model_num
FROM phones AS p
WHERE p.release_date > '2014-09-30';
```
### White space ### White space
@ -170,34 +126,49 @@ spacing is used. Do not crowd code or remove natural language spaces.
#### Spaces #### Spaces
Spaces should be used to line up the code so that the root keywords all end on Spaces should never be used to line up the code so that the root keywords all end on the same character boundary.
the same character boundary. This forms a river down the middle making it easy for * Indentations of 4 spaces are the standard that is utilized throughout the codebase.
the readers eye to scan over the code and separate the keywords from the * All `(` and `)` must be placed on a line of there own unless only operating on two or less items
implementation detail. Rivers are [bad in typography][rivers], but helpful here.
```sql ```sql
(SELECT f.species_name, (
AVG(f.height) AS average_height, AVG(f.diameter) AS average_diameter SELECT
FROM flora AS f species_name,
WHERE f.species_name = 'Banksia' AVG(height) AS average_height,
OR f.species_name = 'Sheoak' AVG(diameter) AS average_diameter
OR f.species_name = 'Wattle' FROM
GROUP BY f.species_name, f.observation_date) FLORA
WHERE
species_name = 'Banksia'
OR
species_name = 'Sheoak'
OR
species_name = 'Wattle'
GROUP BY
species_name,
observation_date
)
UNION ALL UNION ALL
(SELECT b.species_name, (
AVG(b.height) AS average_height, AVG(b.diameter) AS average_diameter SELECT
FROM botanic_garden_flora AS b species_name,
WHERE b.species_name = 'Banksia' AVG(height) AS average_height,
OR b.species_name = 'Sheoak' AVG(diameter) AS average_diameter
OR b.species_name = 'Wattle' FROM
GROUP BY b.species_name, b.observation_date) BOTANIC_GARDEN_FLORA
WHERE
species_name = 'Banksia'
OR
species_name = 'Sheoak'
OR
species_name = 'Wattle'
GROUP BY
species_name,
observation_date
)
``` ```
Notice that `SELECT`, `FROM`, etc. are all right aligned while the actual column
names and implementation specific details are left aligned.
Although not exhaustive always include spaces: Although not exhaustive always include spaces:
* before and after equals (`=`) * before and after equals (`=`)
@ -216,16 +187,15 @@ SELECT a.title, a.release_date, a.recording_date
Always include newlines/vertical space: Always include newlines/vertical space:
* before `AND` or `OR`
* after semicolons to separate queries for easier reading * after semicolons to separate queries for easier reading
* after each keyword definition * after each `VALUE` group in an `INSERT` statement
* after a comma when separating multiple columns into logical groups * to separate code into related sections, which helps to ease the readability of large chunks of code.
* to separate code into related sections, which helps to ease the readability of
large chunks of code. Always on their own line:
* Data manipulation statements should have every clause keyword on a line of its own unless performing extremely simple statements. Examples of the clause keywords are `SELECT`, `DELETE`, `UPDATE`, `FROM`, `WHERE`, `HAVING`, `GROUP BY`, `ORDER BY`, `LIMIT`. An example of a simple single line statements `SELECT COUNT(*) as student_count FROM STUDENTS WHERE graduated = 0;`
* Every field being selected, updated, grouped on or limted by in the query should be on their own line. Unless involved in a functional operation such as an `IF()`, `CASE`, `COALESCE()` ... etc. which require additional fields to function
* `AND` and `OR` should appear on their own lines
Keeping all the keywords aligned to the righthand side and the values left aligned
creates a uniform gap down the middle of query. It makes it much easier to scan
the query definition over quickly too.
```sql ```sql
INSERT INTO albums (title, release_date, recording_date) INSERT INTO albums (title, release_date, recording_date)
@ -234,17 +204,27 @@ VALUES ('Charcoal Lane', '1990-01-01 01:01:01.00000', '1990-01-01 01:01:01.00000
``` ```
```sql ```sql
UPDATE albums UPDATE
SET release_date = '1990-01-01 01:01:01.00000' ALBUMS
WHERE title = 'The New Danger'; SET
release_date = '1990-01-01 01:01:01.00000',
producer_name = NULL
WHERE
title = 'The New Danger';
``` ```
```sql ```sql
SELECT a.title, SELECT
a.release_date, a.recording_date, a.production_date -- grouped dates together title,
FROM albums AS a release_date,
WHERE a.title = 'Charcoal Lane' recording_date,
OR a.title = 'The New Danger'; production_date
FROM
ALBUMS
WHERE
title = 'Charcoal Lane'
OR
title = 'The New Danger';
``` ```
### Indentation ### Indentation
@ -252,42 +232,66 @@ SELECT a.title,
To ensure that SQL is readable it is important that standards of indentation To ensure that SQL is readable it is important that standards of indentation
are followed. are followed.
#### Clause Keywords
* Should be at the top level with the least indentation of anything else contained in their statement.
* These words should be on a line alone
#### Joins #### Joins
Joins should be indented to the other side of the river and grouped with a new * Natural Joins are not allowed ... ever
line where necessary. * A Join type must be indicated `LEFT OUTER`, `RIGHT OUTER`, `INNER`
* Joins should be indented one indent under their tables or sub-queries
* ON clauses should be indented to be left justified with the JOINs
* Multiple ON clauses should be indented to be indented benieth the ON and JOIN keywords
```sql ```sql
SELECT r.last_name SELECT
FROM riders AS r R.last_name
INNER JOIN bikes AS b FROM
ON r.bike_vin_num = b.vin_num RIDERS AS R
AND b.engines > 2 INNER JOIN
BIKES AS B
INNER JOIN crew AS c ON R.bike_vin_num = B.vin_num
ON r.crew_chief_last_name = c.last_name AND
AND c.chief = 'Y'; B.engines > 2
INNER JOIN
CREW AS C
ON R.crew_chief_last_name = C.last_name
AND
C.chief = 'Y';
``` ```
#### Subqueries #### Subqueries
Subqueries should also be aligned to the right side of the river and then laid Subqueries should be aligned with the indentation level that their non-subquery counterpart would reside. Subqueries should begin with a line containing only an opening `(` then the next line being indented 1 indent deeper. The subquery should end with a closing `)` and the alias for that subquery if appropriate. Try and include a commend line to describe the subquery
out using the same style as any other query. Sometimes it will make sense to have
the closing parenthesis on a new line at the same character position as its
opening partner—this is especially true where you have nested subqueries.
```sql ```sql
SELECT r.last_name, SELECT
(SELECT MAX(YEAR(championship_date)) r.last_name,
FROM champions AS c (
WHERE c.last_name = r.last_name SELECT
AND c.confirmed = 'Y') AS last_championship_year MAX(YEAR(championship_date))
FROM riders AS r FROM
WHERE r.last_name IN champions AS c
(SELECT c.last_name WHERE
FROM champions AS c c.last_name = r.last_name
WHERE YEAR(championship_date) > '2008' AND
AND c.confirmed = 'Y'); 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'
);
``` ```
### Preferred formalisms ### Preferred formalisms
@ -302,18 +306,25 @@ SELECT r.last_name,
likely should be. likely should be.
```sql ```sql
SELECT CASE postcode SELECT
CASE postcode
WHEN 'BN1' THEN 'Brighton' WHEN 'BN1' THEN 'Brighton'
WHEN 'EH1' THEN 'Edinburgh' WHEN 'EH1' THEN 'Edinburgh'
END AS city END AS city
FROM office_locations FROM
WHERE country = 'United Kingdom' OFFICE_LOCATIONS
AND opening_time BETWEEN 8 AND 9 WHERE
AND postcode IN ('EH1', 'BN1', 'NN1', 'KW1') country = 'United Kingdom'
AND
opening_time BETWEEN 8 AND 9
AND
postcode IN ('EH1', 'BN1', 'NN1', 'KW1')
``` ```
## Create syntax ## Create syntax
```sql
/* I do not think that this is a nessisary part of a style guide since we generally should not be creating tables in production */
```
When declaring schema information it is also important to maintain human When declaring schema information it is also important to maintain human
readable code. To facilitate this ensure the column definitions are ordered and readable code. To facilitate this ensure the column definitions are ordered and
grouped where it makes sense to do so. grouped where it makes sense to do so.
@ -1283,3 +1294,5 @@ ZONE
"SQL style guide by Simon Holywell" "SQL style guide by Simon Holywell"
[licence]: http://creativecommons.org/licenses/by-sa/4.0/ [licence]: http://creativecommons.org/licenses/by-sa/4.0/
"Creative Commons Attribution-ShareAlike 4.0 International License" "Creative Commons Attribution-ShareAlike 4.0 International License"
[design-guide]: https://auditanalytics.atlassian.net/wiki/spaces/WEBDEV/pages/25198598/Database+Design
"Ives Database Design Guide"