0Pricing
Coding Interview Prep · Lekcja

Generowanie szeregów liczb i dat

Używanie rekurencji do tworzenia sekwencji na potrzeby uzupełniania luk i kalendarzy

Generowanie szeregów liczb i dat to bezpłatna lekcja Coding Interview Prep na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Coding Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.

Rekurencja bez hierarchii

Rekurencyjne CTE służą nie tylko do obsługi drzew. Drugim ważnym zastosowaniem jest generowanie sekwencji: ciągu liczb albo każdej daty z określonego zakresu. Osoby prowadzące rozmowy kwalifikacyjne pytają o to, gdy problem wymaga uzupełniania luk — czyli tworzenia wierszy, które nie istnieją w żadnej tabeli.

Klasyczne polecenie brzmi: „Pokaż sprzedaż dla każdego dnia miesiąca, uwzględniając dni bez sprzedaży”. Nie można wyświetlić brakującego dnia, jeśli najpierw nie wygeneruje się wszystkich dni.

Prosty ciąg liczb

Część kotwicząca inicjuje pierwszą liczbę, część rekurencyjna dodaje jeden w każdej iteracji, a klauzula WHERE w części rekurencyjnej zatrzymuje działanie. W ten sposób generowane są liczby od 1 do 10.

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < 10
)
SELECT n FROM nums;

Predykat zakończenia

W przeciwieństwie do schematu organizacyjnego ciąg liczb nie ma naturalnego węzła końcowego, na którym można się zatrzymać — zwiększanie wartości mogłoby trwać bez końca. Dlatego w części rekurencyjnej trzeba dodać jawny warunek zakończenia: WHERE n < 10.

Gdy n osiągnie wartość 10, klauzula WHERE w następnej iteracji odrzuci jedyny wiersz kandydujący, część rekurencyjna nie zwróci żadnego wiersza, a rekurencja się zatrzyma. Zapomnienie o tym zabezpieczeniu jest najczęstszą przyczyną niekontrolowanej rekurencji podczas rozmów kwalifikacyjnych.

Parametryzowanie zakresu

Elastyczność ciągu można uzyskać, wyznaczając jego granicę na podstawie wartości lub zmiennej. W tym przykładzie generowany jest zakres od 1 do N, gdzie podawana jest wartość N. Ten sam schemat pozwala tworzyć ciągi zaczynające się od 0 lub zwiększane o określony krok — wystarczy zmienić wartość początkową i przyrost.

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 2 FROM nums WHERE n + 2 <= 99
)
SELECT n FROM nums;  -- odd numbers 1,3,5,...,99

Generowanie ciągu dat

Zastąpienie działań na liczbach całkowitych działaniami na datach pozwala uzyskać kalendarz. Datą początkową w części kotwiczącej jest data rozpoczęcia, a część rekurencyjna dodaje jeden dzień, aż przekroczy datę końcową.

Składnia dodawania dnia różni się w zależności od dialektu — przedstawiona forma w stylu Postgres używa interwału.

WITH RECURSIVE cal AS (
    SELECT DATE '2024-01-01' AS d
    UNION ALL
    SELECT d + INTERVAL '1 day'
    FROM cal
    WHERE d < DATE '2024-01-31'
)
SELECT d FROM cal;

Uzupełnianie luk za pomocą LEFT JOIN

Teraz należy połączyć kalendarz z rzeczywistymi danymi. Najpierw generuje się każdy dzień, a następnie wykonuje LEFT JOIN z tabelą sprzedaży, aby brakujące dni pojawiły się z wartością NULL, którą za pomocą COALESCE zamienia się na 0.

Ten dwuetapowy schemat — wygenerowanie szkieletu, a następnie wykonanie lewostronnego złączenia z danymi — stanowi podstawę każdej odpowiedzi dotyczącej uzupełniania luk.

WITH RECURSIVE cal AS (
    SELECT DATE '2024-01-01' AS d
    UNION ALL
    SELECT d + INTERVAL '1 day' FROM cal
    WHERE d < DATE '2024-01-07'
)
SELECT cal.d, COALESCE(SUM(s.amount), 0) AS total
FROM cal
LEFT JOIN sales s ON s.sale_date = cal.d
GROUP BY cal.d
ORDER BY cal.d;

Szkielety miesięczne i tygodniowe

Zmiana przyrostu pozwala tworzyć kalendarze o większych jednostkach. Dodaj INTERVAL '1 month', aby utworzyć szkielet miesięczny, albo INTERVAL '7 day', aby utworzyć szkielet tygodniowy. Jest to przydatne, gdy podczas rozmowy kwalifikacyjnej wymagany jest raport miesięczny uwzględniający również puste miesiące.

WITH RECURSIVE months AS (
    SELECT DATE '2024-01-01' AS m
    UNION ALL
    SELECT m + INTERVAL '1 month' FROM months
    WHERE m < DATE '2024-12-01'
)
SELECT m FROM months;

Różnice między dialektami w operacjach na datach

Operacje arytmetyczne na datach są najmniej przenośną częścią tych zapytań. Warto znać poszczególne warianty:

  • Postgres: d + INTERVAL '1 day'.
  • MySQL: DATE_ADD(d, INTERVAL 1 DAY).
  • SQL Server: DATEADD(DAY, 1, d).
  • SQLite: date(d, '+1 day').

Wspomnienie, że struktura rekurencji pozostaje identyczna i zmienia się tylko funkcja daty, jest mocną odpowiedzią świadczącą o znajomości dialektów.

Rekurencja a generate_series

Postgres zawiera wbudowaną funkcję generate_series(), która generuje liczby lub daty bez użycia rekurencji, a przy tym działa szybciej i zapewnia czytelniejszy kod:

SELECT generate_series(DATE '2024-01-01', DATE '2024-01-31', INTERVAL '1 day');

Jeśli baza danych używana podczas rozmowy kwalifikacyjnej ją obsługuje, warto z niej skorzystać. Wiele silników, w tym MySQL i starsze wersje SQL Server, jej jednak nie obsługuje — właśnie wtedy rekurencyjne CTE jest przenośną alternatywą.

Uważaj na limit rekurencji

Generowanie dużego ciągu może przekroczyć limit rekurencji silnika. SQL Server ma domyślnie ustawione MAXRECURSION 100, dlatego kalendarz obejmujący 365 dni zakończy się błędem, chyba że zostanie do zapytania dopisana opcja OPTION (MAXRECURSION 0), która usuwa limit.

Postgres nie ma stałego limitu, ale niekontrolowane generowanie ciągu z powodu błędnego warunku może trwać aż do wyczerpania pamięci. Przed zwiększeniem skali zawsze należy sprawdzić, czy predykat zakończenia jest poprawny.

-- SQL Server: lift the 100-row recursion cap
-- ...recursive CTE here...
SELECT * FROM cal
OPTION (MAXRECURSION 0);

Łączenie ciągu za pomocą CROSS JOIN

Wygenerowany ciąg jest często tylko składnikiem rozwiązania. Po utworzeniu CTE z liczbami można użyć CROSS JOIN, aby rozszerzać lub rozwijać wiersze — na przykład powielić każdy wiersz zamówienia tyle razy, ile wynosi jego ilość, albo rozwinąć zakres dat osobno dla każdego klienta.

Zrozumienie, że rekurencja tworzy wielokrotnie użyteczny element budulcowy, a nie tylko końcową odpowiedź, odróżnia dopracowaną odpowiedź na rozmowie kwalifikacyjnej od rozwiązania odtworzonego z pamięci.

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < 10
)
SELECT o.order_id, nums.n AS unit
FROM orders o
JOIN nums ON nums.n <= o.quantity;

Szybki test

Dlaczego predykat zakończenia ma kluczowe znaczenie w ciągu liczb lub dat?

Podsumowanie

Rekurencja może tworzyć wiersze, które nie istnieją w żadnej tabeli:

  • Zainicjuj pierwszą wartość w części kotwiczącej, a następnie zwiększaj ją w części rekurencyjnej.
  • Zawsze dodawaj jawny predykat zakończenia — ciągi nie mają naturalnego końca.
  • Zbuduj szkielet dat lub liczb, a następnie wykonaj LEFT JOIN z danymi i użyj COALESCE do uzupełniania luk.
  • Jeśli jest dostępna, wybieraj funkcję generate_series; w SQL Server pamiętaj o MAXRECURSION.

Dalej: techniki zabezpieczające przed niekontrolowanym działaniem rekurencji.

Często zadawane pytania

Czy lekcja „Generowanie szeregów liczb i dat” jest bezpłatna?

Tak — pełny tekst „Generowanie szeregów liczb i dat” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Coding Interview Prep, przejdź na CoddyKit PRO. Kurs Coding Interview Prep zawiera 4 lekcji w sumie.

Co nauczysz się w „Generowanie szeregów liczb i dat”?

Używanie rekurencji do tworzenia sekwencji na potrzeby uzupełniania luk i kalendarzy Ćwiczysz Coding Interview Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Coding Interview Prep?

Nie wymagamy żadnego doświadczenia. Coding Interview Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Generowanie szeregów liczb i dat”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Coding Interview Prep?

Tak. Każda lekcja Coding Interview Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Elementy zakotwiczający i rekurencyjny
  2. Przechodzenie po strukturze organizacyjnej
  3. Generowanie szeregów liczb i dat
  4. Unikanie nieskończonej rekurencji
← Powrót do Coding Interview Prep