Tipy k formátování SQL kódu

Chci se sepsat jak formátovat SQL kód, aby byl pro mě čitelnější a lépe se upravoval.

Vycházím především ze své praxe, co se mi osvědčilo.

Snažím se aby byl kód především dobře čitelný, a dále chci co nejméně psát.

Příkladová data

Vytvořím si na začátek dvě dočasné tabulky, na kterých budu ukazovat. A vložím do nich data.

DROP TABLE IF EXISTS #Organizace --tabulka s organizacemi, (odběrateli)
CREATE TABLE #Organizace (	
	 ID int NOT NULL
	,IC varchar (20) not null
	,NazevOrganizace VARCHAR(200) NOT NULL
)

DROP TABLE IF EXISTS #Faktura --tabulka s fakturami (vydanými) na organizaci.
CREATE TABLE #Faktura (	
	 ID int NOT NULL
	,Cislo varchar (20) not null
	,Datum datetime not null
	,OrganizaceID int NOT NULL
	,VystavilID int NULL
	,Castka money NOT NULL
)

DROP TABLE IF EXISTS #Zamestnanci --tabulka se zaměstnanci.
CREATE TABLE #Zamestnanci (	
	 ID int NOT NULL
	,PrijmeniJmeno varchar (20) not null
)

INSERT INTO #Organizace (ID,IC,NazevOrganizace)
VALUES 
 (1,'11111','PanKostka s.r.o.')
,(2,'22222','Nabla a.s.')
,(3,'33333','Fake a.s.')

INSERT INTO #Faktura (ID,Cislo,Datum,OrganizaceID,VystavilID,Castka)
VALUES 
 (1,'2020/01','2020-03-01',1,1,1000)
,(2,'2020/02','2020-03-01',2,1,500)
,(3,'2020/03','2020-03-01',1,2,2500)
,(4,'2020/04','2020-03-01',3,2,7333)

INSERT INTO #Zamestnanci (ID,PrijmeniJmeno)
VALUES 
 (1,'Dvořák Jiří')
,(2,'Dvořáková Zuzana')

A1 Čárky na začátek

Čárky pro oddělování sloupců nedávat na konec, ale na začátek. Tím že je napíšu na začátek, na první pohled vidím, kde chybí. V níže uvedeném SQL je jedna čárka vynechána. Schválně kde to najdu rychleji?

Než jsem začal psát čárky na začátek, moje nejčastější chyba byla Incorrect syntax near ‚,‘. Nedělal jsem nic jiného, než hledal čárky.

-------------- Čárky na začátku - OK -------------------
SELECT 
	 f.Cislo
	,f.Datum
	 o.NazevOrganizace
	,f.Castka
FROM #Faktura f
LEFT OUTER JOIN #Organizace o on o.ID = f.OrganizaceID

-------------- Čárky na konci - KO -------------------
SELECT 
	f.Cislo,
	f.Datum,
	o.NazevOrganizace
	f.Castka
FROM #Faktura f
LEFT OUTER JOIN #Organizace o on o.ID = f.OrganizaceID

Můj oblíbený online formátovač poorsql.com to dělá stejně.

A2 Nelogická podmínka WHERE 1=1

Většinou mám v selectu více podmínek za WHERE. A často potřebuji některou z podmínek zakomentovat. Pokud první podmínku napíšu hned za WHERE, nejde jednoduše zakomentovat. Proto si pomáhám formulací WHERE 1=1 a podmínky jsou pak každá na samostatném řádku a začíná AND.

SELECT 
	 f.Cislo
	,f.Datum
	,f.Castka
FROM #Faktura f
WHERE 1=1
--AND Castka <> 0	--TOTO JE ZAKOMENTOVÁNO
AND Datum > '2020-01-01'

Výhodou je nejen snažší komentování, ale i přehlednost. Taky většinou to WHERE nezapomenu (Pokud jsou poslední podmínky na spojení tabulek a já přidám podmínku AND (bez WHERE), select projde, ale vrací něco úplně jiného )

A3 OR vždy v závorce

Standardní podmínky za WHERE (nebo při spojování tabulek) jsou nejčastěji AND Něco. Omezují počet řádků, které mi SELECT vrací. Ale někdy je potřeba dát i OR. Typicky to bývá když je někde výčet hodnot.

Třeba chci všechny faktury nad 1000 na organizaci A NEBO (=OR) organizaci B.

Bez výjimky, jakmile se vyskytne OR, dávám OR do závorek. A snažím se ho oddělit, abych nenarušil podmínky AND.

SELECT 
	 f.Cislo
	,f.Datum
	,f.Castka
FROM #Faktura f
WHERE 1=1
AND Castka <> 0	
AND (f.organizaceID = 1 OR f.OrganizaceID = 2) --OR musí být vždy v závorce.
AND Datum > '2020-01-01'

A4 Psaní JOIN

Nově budu psát LEFT JOIN. Dříve jsem psal LEFT OUTER JOIN, ale je to stejné a je to zbytečné slovo navíc.
Používám tak ze 70%. Nejčastější spojovací podmínka. Mám tabulku a k ní dotahuji další.

Nikdy nepoužívám RIGHT JOIN. Nedává to smysl.

Píšu JOIN nikoli INNER JOIN. To slovo je zbytečné.
Používám tak z 20%. Obvykle když je vazba před ID které je povinné. A i tak si to promýšlím. Obvykle vycházím z jedné tabulky a přitahuji další. Když použiji LEFT JOIN, vím že SELECT vrátí z výchozí tabulky všechny záznamy a kde podmínka není splněna bude null. Pokud bych dal JOIN a podmínka nebude splněna, ořeže mi to i výchozí tabulku, což obvykle nechci.

Píšu FULL JOIN místo FULL OUTER JOIN.
Používám velmi zřídka, cca 5% případů. Typicky na reporty kde se porovnávají dva sety. Kde potřebuji vidět obě tabulky a kde se nesetkávají. Kdysi jsem používal porovnání zleva a zprava (přesněji zleva a zleva při obrácených tabulkách, nikdy RIGHT JOIN).

Píšu CROSS JOIN aby bylo jasné že se jedná o kartézský součin. Dříve jsem psal prostě JOIN bez spojovací podmínky a do komentáře jsem tučně psal — POZOR KARTÉZSKÝ SOUČIN!.
Používám velmi zřídka, cca 2% případů. Většinou v OLAP kostkách, třeba analýza nákupního košíku nebo rozgenerování záznamů do času apod.

Starou syntaxi, kdy se dává spojení tabulek do WHERE (místo JOIN) jsem použil tak před deseti lety.

A5 Podmínky za JOIN do jednoho řádku

Podmínky spojení za ON píšu do jednoho řádku (obvykle). Je to jinak než se obvykle doporučuje. Pro mě je ten kód výrazně přehlednější, protože když čtu co ten select dělá, nejprve procházím jaké tabulky se připojují a pak teprve zkoumám jak. Pokud je podmínka spojení nějak výjimečné nebo atypická, dávám na konec komentář. Pokud je těch podmínek hodně, první dám normálně a ty další no nové řádky ale pod tu první. Pořád chci vidět tabulky nejdříve.

SELECT f.Cislo
	,f.Datum
	,o.NazevOrganizace
	,z.PrijmeniJmeno
	,f.Castka
FROM #Faktura f
LEFT JOIN #Organizace o
	ON o.ID = f.OrganizaceID
LEFT JOIN #Zamestnanci z
	ON z.id = f.VystavilID

--Toto se líbí mě
SELECT 
	f.Cislo
	,f.Datum
	,o.NazevOrganizace
	,z.PrijmeniJmeno
	,f.Castka
FROM #Faktura f
LEFT OUTER JOIN #Organizace o on o.ID = f.OrganizaceID
LEFT OUTER JOIN #Zamestnanci z on z.id = f.VystavilID

V mém oblíbeném poorsql je to volba “ Break Join ON Sections“ která je implicitně nazaškrtnutá = jako to používám já.

A6 Keywords klidně malými

Klíčová slova jako SELECT, WHERE, FROM, CASE, atd. by se měla psát velkými písmeny. Obvykle to moc neřeším, protože je mám všude barevně zvýrazněná a obvykle to stačí. Něco píšu opravdu vždy velkými (typicky CASE, WHERE, END) něco různě (select, from).

-- Keywords malými podle mě není takový problém
select 
	f.Cislo
	,f.Datum
	,o.NazevOrganizace
	,f.Castka
from #Faktura f
left join #Organizace o on o.ID = f.OrganizaceID
where 1=1

-- Keywords velkými
SELECT 
	f.Cislo
	,f.Datum
	,o.NazevOrganizace
	,f.Castka
FROM #Faktura f
LEFT JOIN #Organizace o ON o.ID = f.OrganizaceID
WHERE 1=1

A7 Pomocné select top 100 *

V selectu (ale i updatu) si velmi často si nechávám na konci sloupců pomocné řádky.
— SELECT TOP 100 *
— SEELCT TOP 100 f.*
— SELECT count(*)

SELECT 
	f.Cislo
	,f.Datum
	,o.NazevOrganizace
	,f.Castka
-- SELECT TOP 100 * 
-- SELECT TOP 100 f.*
-- SELECT COUNT(*)
FROM #Faktura f
LEFT JOIN #Organizace o ON o.ID = f.OrganizaceID
WHERE 1=1

Když se pak chci podívat na počet záznamů, vyznačím si jen odpovídající část. Zrychluje to ladění, z výsledku selectu si můžu nakopírovat názvy sloupců (pravé tlačítko na záhlaví výsledku/Copy with headers) apod.

A8 V proceduře dávám parametry

Uložená procedura s parametry se hůř ladí, protože ty parametry/proměnné jsou deklarované na začátku. Obvykle ty parametry/proměnné vydeklaruji znovu zakomentované takto:
/*
Declare @parametr Char(1) = ‚A‘
— */
Finta je v tom zakomentování komentáře pomocí –. Prioritu má totiž */ ale jen pokud se najde začátek. Takže když vyznačím kód od toho Declare, krásně to projde.

-- Toto nemá vliv na běh procedury
/*
Declare @parametr1 char(1) = 'A'
-- */

-- a pokud vyznačím jen níže uvedenou část, je to opět korektní.
Declare @parametr1 char(1) = 'A'
-- */

A9 Update vždy nejprve jako select

Nikdy nepíšu rovnou UPDATE/DELETE. Vždycky píšu nejprve SELECT, podívám se na výsledek a počet záznamů a pak ten select změním na UPDATE/DELETE.

UPDATE f SET
	f.Castka = 5000
-- SELECT f.Cislo,f.Datum,o.NazevOrganizace,f.Castka
FROM #Faktura f
LEFT OUTER JOIN #Organizace o on o.ID = f.OrganizaceID
WHERE 1=1
AND f.Cislo = '2020/01'

DELETE f
-- SELECT f.Cislo,f.Datum,o.NazevOrganizace,f.Castka
FROM #Faktura f
LEFT OUTER JOIN #Organizace o on o.ID = f.OrganizaceID
WHERE 1=1
AND f.VystavilID  = 2

A10 Vyhýbám se mezerám za čárkou

Normálně prostě sloupce oddělené čárkou, mezera je tam zbytečná. Čsto mám v selectu desítky sloupců, čím kratší tím lepší. Posunování pomocí CTRL + šipka funguje správně, vyznačení doubleclickem taky.

-- Sloupce prostě oddělené čárkami
INSERT INTO #Organizace (ID,IC,NazevOrganizace)
--Toto je zbytečně dlouhé
INSERT INTO #Organizace (ID, IC, NazevOrganizace)

A11 Komentuji

Opravdu hodně komentuji. Až extrémně hodně. V proceduře před každým updateme, selectem píšu co vlastně chci. Když potom čtu tu uloženou proceduru, čtu nejprve co ten kód má dělat (komentář) a pak teprve co skutečně dělá. Dost často se stává, že už tímto objevím chybu.

Používám komentáře jak v řádku –, tak uvnitř /**/

Pro oddělení kusů kódů používám
–***************************** Text **********************************
———————- Text
–Text

Závěr

Nějak jsem se rozepsal víc než jsem myslel. A ještě mi toho dost zbylo. Snad se k tomu někdy dostanu.
Rád bych si sepsal jmenné konvence (naming conventions) jaké mi vyhovují (CamelToe CamelCase rules!, primární klíč jen ID! atd.)
Název sloupce (tabulky) s diakritikou musí být v hranatých závorkách []. Používá se velmi zřídka (třeba když odesílám TMP tabulku mailem).

Linky

Pro další tipy se snažím googlit na klíčová slova „sql syntax best practices“, „Formátování SQL“.

* sqlstyle.guide – Většina těch zásad mi připadá přesně obráceně než používám. Nelíbí se mi to moc.
* dzone.com/24-rules-to-the-sql-formatting-standard


Posted

in

,

by

Tags:

Comments

Napsat komentář

[zoom]