Valmistautuminen ohjelmointihaastatteluihin · Oppitunti

Luku- ja päivämääräsarjojen luominen

Käytä rekursiota aukkojen täyttämiseen ja kalentereiden luomiseen tarvittavien sarjojen muodostamiseen

Oppitunti 3/413 vaihetta

Luku- ja päivämääräsarjojen luominen on ilmainen Valmistautuminen ohjelmointihaastatteluihin-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Valmistautuminen ohjelmointihaastatteluihin-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Valmistautuminen ohjelmointihaastatteluihin-kurssilla on yhteensä 4 oppituntia.

Rekursio ilman hierarkiaa

Rekursiiviset CTE:t eivät ole tarkoitettu vain puille. Toinen tärkeä käyttötarkoitus on sarjojen muodostaminen: lukujen peräkkäinen sarja tai jokainen päivämäärä tietyllä aikavälillä. Haastatteluissa tästä kysytään, kun tarvitaan aukkojen täyttämistä — eli muodostetaan rivejä, joita ei ole missään taulussa.

Klassinen tehtävä kuuluu: "Näytä kuukauden myynti päivittäin ja sisällytä myös päivät, jolloin myyntiä ei ollut." Puuttuvaa päivää ei voi näyttää, ellei kaikkia päiviä ensin muodosteta.

Yksinkertainen lukusarja

Ankkuri alustaa ensimmäisen luvun, rekursiivinen jäsen lisää jokaisella iteraatiolla yhden, ja rekursiivisen jäsenen WHERE-ehto pysäyttää suorituksen. Näin muodostetaan luvut 1–10.

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

Lopetusehto

Toisin kuin organisaatiokaaviolla, lukusarjalla ei ole pysäytettäväksi luonnollista lehtisolmua — lukuja voisi kasvattaa loputtomiin. Siksi rekursiiviseen jäseneen on lisättävä eksplisiittinen lopetusehto: WHERE n < 10.

Kun n saavuttaa arvon 10, seuraavan iteraation WHERE-ehto suodattaa ainoan ehdokasrivin pois, rekursiivinen jäsen ei palauta mitään ja rekursio päättyy. Tämän ehdon unohtaminen on haastatteluissa yleisin syy hallitsemattomaan rekursioon.

Alueen parametrisoiminen

Sarjasta tehdään joustava määrittämällä yläraja arvon tai muuttujan avulla. Tässä muodostetaan sarja 1:stä annettuun N:ään. Sama rakenne tuottaa nollasta alkavia tai harvennettuja sarjoja — muuta vain ankkuria ja askelta.

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

Päivämääräsarjan muodostaminen

Kun kokonaislukulaskenta vaihdetaan päivämäärälaskentaan, saadaan kalenteri. Ankkuri on aloituspäivämäärä, ja rekursiivinen jäsen lisää yhden päivän, kunnes päivämäärä ylittää lopetuspäivämäärän.

Päivän lisäämisen syntaksi vaihtelee SQL-murteittain — tässä Postgres-tyylisessä muodossa käytetään intervallia.

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;

Aukkojen täyttäminen LEFT JOIN -liitoksella

Yhdistetään nyt kalenteri todelliseen dataan. Muodostetaan jokainen päivä ja liitetään sitten myyntitauluun LEFT JOIN, jotta puuttuvat päivät näkyvät arvolla NULL, joka muutetaan COALESCE-funktion avulla nollaksi.

Tämä kaksivaiheinen malli — muodostetaan runko ja liitetään sitten faktat vasemmalta — on jokaisen aukkojen täyttämistä koskevan ratkaisun ydin.

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;

Kuukausi- ja viikkorungot

Muodostetaan karkeampia kalentereita muuttamalla askelta. Lisää INTERVAL '1 month' kuukausirunkoa varten tai INTERVAL '7 day' viikkoja varten. Tämä on hyödyllistä, kun haastattelija haluaa kuukausittaisen raportin, joka sisältää myös tyhjät kuukaudet.

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;

Päivämääräaritmetiikan murre-erot

Päivämääräaritmetiikka on näiden kyselyiden vähiten siirrettävä osa. Tunne eri muodot:

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

Vahva, SQL-murteen huomioiva vastaus mainitsee, että rekursion rakenne on sama ja vain päivämääräfunktio vaihtuu.

Rekursio ja generate_series

Postgres sisältää valmiin generate_series()-funktion, joka muodostaa lukuja tai päivämääriä ilman rekursiota. Se on nopeampi ja selkeämpi:

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

Jos haastattelijan käyttämä tietokanta tukee sitä, sitä kannattaa käyttää. Monet tietokantamoottorit, kuten MySQL ja aiemmat SQL Server -versiot, eivät kuitenkaan tue sitä — juuri silloin rekursiivinen CTE on siirrettävä vararatkaisu.

Rekursioraja on huomioitava

Suuren sarjan muodostaminen voi saavuttaa tietokantamoottorin rekursiorajan. SQL Serverin oletusarvo on MAXRECURSION 100, joten 365 päivän kalenterin muodostaminen epäonnistuu, ellei rajoitusta poisteta lisäämällä loppuun OPTION (MAXRECURSION 0).

Postgresissa ei ole kiinteää rajaa, mutta väärän lopetusehdon vuoksi hallitsematon sarja voi jatkua muistin loppumiseen asti. Lopetusehdon oikeellisuus on aina varmistettava ennen sarjan kasvattamista.

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

Sarjan ristiinliittäminen

Muodostettu sarja on usein vain yksi osa ratkaisua. Kun lukujen CTE on käytettävissä, se voidaan yhdistää CROSS JOIN -liitoksella rivien laajentamiseen tai monistamiseen — esimerkiksi kunkin tilausrivin toistamiseen sen määrän verran tai päivämäärävälin muodostamiseen kullekin asiakkaalle.

On tärkeää ymmärtää, että rekursio tuottaa uudelleenkäytettävän rakennuspalikan eikä vain lopullista vastausta. Tämä erottaa huolellisesti laaditun haastatteluvastauksen ulkoa opetellusta vastauksesta.

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;

Pikatarkistus

Miksi lopetusehto on ratkaisevan tärkeä luku- tai päivämääräsarjassa?

Kertaus

Rekursiolla voidaan muodostaa rivejä, joita ei ole missään taulussa:

  • Alusta ensimmäinen arvo ankkurissa ja kasvata sitä rekursiivisessa jäsenessä.
  • Lisää aina eksplisiittinen lopetusehto — sarjoilla ei ole luonnollista päätepistettä.
  • Muodosta päivämäärä- tai lukurunko, liitä sitten faktat LEFT JOIN -liitoksella ja täytä aukot COALESCE-funktion avulla.
  • Suosi generate_series-funktiota, jos se on käytettävissä, ja huomioi SQL Serverin MAXRECURSION.

Seuraavaksi käsitellään turvallisuustekniikoita, joilla rekursion hallitsematon jatkuminen estetään.

Aloita maksutta

Opi Valmistautuminen ohjelmointihaastatteluihin tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
90
Oppitunnit
360

Usein kysytyt kysymykset

Onko oppitunti ”Luku- ja päivämääräsarjojen luominen” ilmainen?

Kyllä – oppitunnin ”Luku- ja päivämääräsarjojen luominen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Valmistautuminen ohjelmointihaastatteluihin-kurssin, päivitä CoddyKit PROhon. Valmistautuminen ohjelmointihaastatteluihin-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Luku- ja päivämääräsarjojen luominen”?

Käytä rekursiota aukkojen täyttämiseen ja kalentereiden luomiseen tarvittavien sarjojen muodostamiseen Harjoittelet Valmistautuminen ohjelmointihaastatteluihin-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Valmistautuminen ohjelmointihaastatteluihin-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Valmistautuminen ohjelmointihaastatteluihin-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Luku- ja päivämääräsarjojen luominen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Valmistautuminen ohjelmointihaastatteluihin-oppitunnilla?

Kyllä. Jokainen Valmistautuminen ohjelmointihaastatteluihin-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Ankkuri- ja rekursiiviset osat
  2. Organisaatiokaavion läpikäynti
  3. Luku- ja päivämääräsarjojen luominen
  4. Päättymättömän rekursion välttäminen
← Takaisin: Valmistautuminen ohjelmointihaastatteluihin