MS Access - Funkce FIRST a LAST

11. 4. 2013, Vladimír Klaus, přečteno 3797x

MS Access
SQL

Pomocí těchto funkcí získáme první, resp. poslední záznam z tabulky či dotazu.

Vezměme jednoduchý příklad, kdy budeme chtít zjistit datum první a poslední objednávky.

SELECT FIRST(Datum), LAST(Datum) FROM Objednavky

FirstLast

Na první pohled to vypadá v pořádku, jen je třeba dát pozor na to, že jde opravdu o hodnotu data z prvního, resp. posledního záznamu. Vůbec to nesouvisí s tím, kdy byla učiněna první, resp. poslední objednávka, i když to tak může vypadat. K tomu slouží funkce MIN a MAX.

Pokud totiž nyní přidám do tabulky objednávek novou, která bude mít datum třeba 1. 1. 2012, dopadne to takto.

FirstLast

Asi vás napadne, že by stačilo přidat řazení dle data, čímž by se situace vyřešila.

SELECT FIRST(Datum), LAST(Datum) FROM Objednavky ORDER BY Datum

Jenže takhle to nepůjde. Dotaz nejprve najde datum z prvního, resp. posledního záznamu a teprve tento výsledek se pokusí seřadit. Ale ve výsledku žádný sloupec Datum není a ani nemůže být. MS Access o tom informuje docela zmatenou hláškou.

FirstLast

Dalším logickým krokem by bylo nejprve provést poddotaz s řazením a na ten pustit hlavní dotaz.

SELECT FIRST(Datum), LAST(Datum)
  FROM (SELECT Datum Objednavky ORDER BY Datum)

Ač je dotaz korektní, dostaneme bohužel opět původní výsledek. Důvodem je to, že to má tak MS Access od verze 2002 nastaveno – záznamy vrací v chronologickém pořadí, jak byly vloženy, a řazení nemá žádný vliv. Před použitím těchto funkcí si vždy ověřte, jak k tomu přistupuje vaše databáze!

Vypadá to, že s funkcemi FIRST a LAST se výsledku nedobereme. Existuje ale možnost, jak je obejít – použitím predikátu TOP. To se může hodit především v případě, že vaše databáze funkce FIRST a LAST nepodporuje.

SELECT TOP 1 Datum FROM Objednavky

SELECT TOP 1 Datum FROM Objednavky ORDER BY Datum DESC

Daleko horší ovšem bude dostat hodnoty do jednoho výsledku. Nejprve připravíme dva samostatné dotazy a pojmenujeme je jako Tabulka1 a Tabulka2. Aby bylo možné tabulky spojit, musí existovat sloupec, na základě kterého dojde ke spojení. Ale takový nemáme. Přidáme proto do obou dotazů nové konstantní sloupce PomID. Celé to pak obalíme hlavním dotazem, který zobrazí obě požadovaná data. Výsledný dotaz pak vypadá takto.

SELECT Datum1, Datum2 FROM
    (SELECT TOP 1 Datum AS Datum1, 1 AS PomID
    FROM Objednavky ORDER BY Datum) Tabulka1
  INNER JOIN
    (SELECT TOP 1 Datum AS Datum2, 1 AS PomID
    FROM Objednavky ORDER BY Datum DESC) Tabulka2
  ON Tabulka1.PomID=Tabulka2.PomID

FirstLast

Jak ale vidíte, opět to není ono, protože máme mezi objednávkami i takové, které nemají datum vyplněné. To je sice z hlediska řazení nejmenší hodnota, ale tu jsme asi nehledali. Další úpravy dotazu už provádět nebudeme, protože to zjevně nemá smysl.

Plyne z těchto příkladů nějaké poučení? Ano, vždy používejte funkce odpovídající potřebám a umožňující korektně získat daný údaj, ale hlavně si vždy ověřte, jak funkce pracují ve vaší databázi.

SELECT MIN(Datum) AS Nejmensi, MAX(Datum) AS Nejvetsi,
  FIRST(Datum) AS PrvniZaznam, LAST(Datum) AS PosledniZaznam
  FROM Objednavky

FirstLast