Stary pies uczy się nowej sztuczki

https://xpil.eu/6cMvg

Mówią, że się nie da, ale czasem da się.

Przytrafiło mi się jakiś czas temu w pracy, że znów - jak za starych, dobrych czasów - piszę dużo kodu SQL. Kod ów działa lepiej lub gorzej, ale ja dziś nie o tym.

Dziś - o formatowaniu.

Szkół jest kilka. W odróżnieniu od takiego, dajmy na to, Pythona, Javy czy C#, gdzie format kodu został zestandaryzowany wieki temu i wszyscy się tego standardu (pi x oko) trzymają, o tyle w przypadku SQL programiści nie mogą się dogadać i każdy ciągnie w swoją stronę.

Pociągnę więc i ja.

Jakiś czas temu odkryłem stronę SQL Style Guide, która pokazuje pewien konkretny styl formatowania zapytań SQL, zaproponowany przez Simona Holywella. Bardziej z nudów i dla hecy niż z przekonania zacząłem przerabiać niektóre ze swoich zapytań na ten właśnie styl - i kliknęło!

Tajemnica polega na tym, że tworzymy rzeki.

Rzeki w tym konkretnym kontekście nie są wprawdzie tak piękne, jak w powyższej piosence - ale jednak są całkiem niebrzydkie.

Przykład:

SELECT tytuł
     , autor
     , rok_wydania
  FROM książki
 WHERE tytuł = 'Cyberiada';

Widać? No przecież, że widać. Po słowie kluczowym pojawia się pionowa "rzeka", wszystko na lewym brzegu jest wyrównane do prawej i vice versa.

Weźmy odrobinę bardziej skomplikowany przypadek:

SELECT B.title AS BookTitle
     , A.name AS AuthorName
     , L.language AS Language
  FROM books AS B
 INNER JOIN authors AS A
    ON B.author_id = A.id
 INNER JOIN languages AS L
    ON B.language_id = L.id
 WHERE A.active = 1
 ORDER BY B.title;

Oczywiście czym dłuższe zapytanie, tym trudniej utrzymać "rzekę" w jednym kawałku, dlatego czasem trzeba podjąć decyzję o "złamaniu" rzeki:

WITH UpdatedBooks AS (
    SELECT B.id AS BookID
         , B.title AS NewTitle
      FROM books AS B
     INNER JOIN authors AS A
        ON B.author_id = A.id
     WHERE A.active = 0
       AND B.updated_at < DATEADD(year, -1, GETDATE())
     UNION ALL
    SELECT B.id
         , B.title
      FROM books AS B
     INNER JOIN languages AS L
        ON B.language_id = L.id
     WHERE L.language = 'English'
       AND B.pages > 300
)
UPDATE B
   SET B.title = U.NewTitle
  FROM books AS B
 INNER JOIN UpdatedBooks AS U
    ON B.id = U.BookID
 WHERE B.title != U.NewTitle;

W ostatnim przykładzie mamy dwie "rzeki": jedna wewnątrz podzapytania CTE, druga na końcu. No i sama linia otwierająca CTE również nie jest częścią "rzeki". Niektórzy idą w skrajność i przesuwają słówko "WITH" żeby "pasowało", ale osobiście uważam powyższy wariant za bardziej czytelny.

  WITH UpdatedBooks AS ( -- tu WITH kończy się na wysokości SELECT
SELECT B.id AS BookID
     , B.title AS NewTitle
  FROM books AS B
  ...

Gwoli ścisłości, podlinkowana na początku artykułu strona o formatowaniu kodu SQL mówi nie tylko o "rzekach", ale również wielu innych elementach, które jednak postanowiłem zignorować, bo mi się tak podoba.

A Ty, Czytelniku, jak formatujesz swój kod SQL?

https://xpil.eu/6cMvg

5 komentarzy

  1. Nie formatuję w ogóle, bo nie umiem w bazodanowe relacje, ale chcę się wkrótce nauczyć. Na start polecasz eksperymenty z MySQL czy od razu PostgreSQL?

    1. Na start polecam próbę rozwiązania jakiegoś konkretnego problemu. Uczenie się samego SQL-a (czy dowolnej innej technologii komputerowej) „na sucho” tj. bez konkretnej potrzeby na ogół nie zdaje egzaminu.

      Rzekłszy jednakowoż powyższe oraz zerknąwszy we własną przeszłość, gdybym dziś startował w te klocki i miałbym wybrać między tymi dwoma silnikami, postawiłbym na PG.

      Miej też na uwadze, że poszczególne dialekty SQL w warstwie podstawowej nie różnią się między sobą aż tak bardzo. Jeżeli załapiesz podstawy na PGSQL, powinieneś w miarę bezproblemowo przesiąść się na MySQL, SQLite czy cokolwiek innego. Oczywiście jak się zaczniesz zagłębiać w bardziej zaawansowane kawałki, prędzej czy później odkryjesz spore różnice, ale podstawy są tu i tam te same.

      Sam rzeźbię od lat w MSSQL, gdzieś tam po drodze miałem krótką przygodę z MySQL oraz nieco dłuższą z Oracle, ale MSSQL zawsze do mnie wraca, jak bumerang.

  2. Formatowanie SQL dla mnie powinno być takie aby:
    – widać jasno boki
    – widać zagnieżdżenia bloków (co jest wewnątrz czego)
    – widać części warunków – odpowiednie ułożenie zagnieżdżonych warunków np. AND na początek
    Do tego dochodzą kwestie estetyczne jak pokazałeś:
    – równać do lewej czy do środka.
    To są już rzeczy jak komu pasuje. Mam doczynienia zazwyczaj z kilkudziesięcioma/kilkuset linijkowymi wykwitami także chyba mam doświadczenie.

    … Jednak przecinki przed wg mnie są jakimś antywzorcem (mimo, że jak dopisujemy coś to ruszamy tylko właściwą linie, a nie linie przed). Moje serce roni łzy na sam widok. 😉

  3. Niezbyt mi się to widzi. Po pierwsze, wyrównywanie słów na początku do prawej jest niewygodne, bo trzeba każdorazowo brać pod uwagę ile liter ma dane słowo. W ogóle zresztą wszelkie wyrównywanie słów ma ten feler, że jak kiedyś dodasz nowe, dłuższe od któregokolwiek z obecnych, to trzeba poprawiać całość. Po drugie, przecinki na początku linijek to zło i niekonsekwencja, skoro pierwsza kolumna jest w linii z SELECT – już lepiej mieć każdą kolumnę w nowej linijce i przecinek na końcu (fakt, wtedy dla odmiany jest niekonsekwencja z brakiem przecinka po ostatniej kolumnie, bo SQL nie ogarnia nadmiarowych przecinków, niemiło z jego strony). Po trzecie, logika jest zaburzona przez przypadki typu INNER JOIN czy UNION ALL, które powinny być w całości po lewej, a nie przedzielone „rzeką” pośrodku. Po czwarte i najpoważniejsze, w tym układzie całkowicie nieczytelna jest hierarchia elementów, np. UNION ALL zaczyna się gdzieś pośrodku i w ogóle nie rzuca się w oczy. Zalet za bardzo nie widzę, poza tym że można sobie narysować ładną pionową kreskę na screenshocie – co chyba jednak wad nie równoważy.

    1. Wyrównanie „do środka” spotkałem produkcyjnie prawie 20 lat temu i czuję, że to było odziedziczone z poprzednich języków przed SQL.
      Wygląda to ładnie, gdyby zapytanie się nie zmieniało w czasie (lub gdybyśmy pracowali bez systemu kontroli wersji, co pewnie kiedyś było czymś częstym, i mielibyśmy czas na taką rearanżację całości). Byłoby jak w książce.
      No i gdyby edytor to wspierał i sam wyrównywał w ten sposób.
      Większość nowych osób w zespole wyrównywało do lewej.

Leave a Comment

Komentarze mile widziane.

Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]

Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.