Jako Loop můžeme označit opakované volání části kódu s různými parametry a většinou je spojen s nějakou DML operací typu INSERT nebo UPDATE. Cyklus voláme po předem stanovený počet opakování a můžeme ho v SQL sestavit několika různými způsoby. Na příkladu s kalendářem si ukážeme všechny způsoby.
Jak na Generování kalendáře v SQL pomocí cyklu?
Dejme tomu, že bychom si chtěli vyrobit v databázi tabulku s kalendářem od 1.1.1980 do 31.12.2050. Kalendář se dá do databáze pochopitelně založit i elegantnějšími způsoby než použitím cyklu, berme to jako cvičení.
Založení prázdné tabulky s kalendářem jako příprava:
CREATE TABLE #Calendar(
[Datum] [Date] PRIMARY KEY,
[DenRoku] AS (DATEPART(DAYOFYEAR,[Datum])),
[DenTydne] AS (DATEPART(WEEKDAY,[Datum])),
[Mesic] AS (DATENAME(MONTH,DATEADD(MONTH,DATEPART(MONTH,[Datum]),(0))-(1))),
[Kvartal] AS (CONCAT(DATEPART(QUARTER,[Datum]),'Q')),
[Rok] AS (DATEPART(YEAR,[Datum]))
);
Tempovou tabulku pro účely příkladu zakládáme s calculated fieldy abychom nemuseli opakovaně vkládat celý seznam polí, ale pouze [Datum]. Po založení tabulky tímto způsobem stačí vkládat jednotlivé datumy a zbytek polí se posléze automaticky dopočítá.
Způsob – GOTO metoda
Tento způsob není příliš doporučován, protože je pomalejší než ostatní. Spočívá v definici label (např. “SQL_CYKLUS_START:”) ke kterému se prostřednictvím příkazu GOTO v jednotlivých iteracích vracíme.
DECLARE @datum_plovouci AS SMALLDATETIME = '1980-01-01';
DECLARE @datum_zarazka AS SMALLDATETIME = '2050-12-31';
SQL_CYKLUS_START:
INSERT INTO #Calendar ([datum])
VALUES(@datum_plovouci)
SET @datum_plovouci = @datum_plovouci+1
IF @datum_plovouci < @datum_zarazka
GOTO SQL_CYKLUS;
SELECT * FROM #Calendar;
WHILE/BEGIN/END Cyklus
WHILE příkazem provádíme opakované volání kódu následujícího po while (většinou odděleného BEGIN/END) a to do doby dokud platí podmínka následující po WHILE
/*promažeme záznamy v naší tabulce a vložíme datumy jinám zpusobem*/
TRUNCATE TABLE #Calendar;
DECLARE @datum_plovouci AS SMALLDATETIME = '1980-01-01'
DECLARE @datum_zarazka AS SMALLDATETIME = '2050-12-31'
WHILE @datum_plovouci< @datum_zarazka
BEGIN
INSERT INTO #Calendar ([datum])
VALUES(@datum_plovouci)
SET @datum_plovouci=@datum_plovouci+1
END;
Rekurzivní CTE (Common table expression)
Rekurzivní CTE jsou zdaleka nejrychlejším způsobem jak dosáhnout výsledku:
/*promažeme záznamy v naší tabulce a vložíme datumy jinám zpusobem*/
TRUNCATE TABLE #Calendar;
DECLARE @datum_plovouci AS SMALLDATETIME = '1980-01-01';
DECLARE @datum_zarazka AS SMALLDATETIME = '2050-12-31'
;WITH [CTE_Date] ([Datum]) AS (
SELECT @datum_plovouci AS DATUM
UNION ALL
SELECT [DATUM]+1 AS DATUM
FROM [CTE_Date]
WHERE [DATUM] + 1<@datum_zarazka
)
INSERT INTO #Calendar
SELECT * FROM [CTE_Date] OPTION (MAXRECURSION 32767);
Více se o rekurzivních dotazech můžete dozvěděl z webu Microsoftu