sobota, 1 sierpnia 2015

Pseudorekurencja w SqlServer

Już dawno nie miałem styczności z SqlServerem więc muszę sobie przypomnieć. Dla treningu zrobiłem zapytanie rekurencyjne (pseudorekurencje). Już taki skrypt wykonałem dla Oracla i muszę powiedzieć, że kod wygląda identycznie :)
Dla problemu liczby fibonacciego tworzymy CTE:
WITH Fibonacci_cte  AS
(
     SELECT 0 as PrevFibN, 1 as FibN, 1 as Nr
     UNION ALL

     SELECT FibN, PrevFibN + FibN, Nr+1
     FROM Fibonacci_cte
     WHERE FibN < 1000000000
)
select * from Fibonacci_cte

Wynik zapytania wygląda tak:
Dla problemu wieży Hanoi mamy model:
with Hanoi_cte   AS 
(
select 
1 as n,
1 as counts

union all

select n +1 as n, POWER(2, n+1) -1 as counts
from Hanoi_cte 
where n < 30
)
select * from Hanoi_cte  

Wyniki zapytania są poniżej:
W tych przykładach dostaje często wyjątek związany z przekroczeniem dozwolonej wielkości dla typu kolumny (int).
Arithmetic overflow error for type int, value = 2147483648.000000.
Możemy zmienić typ kolumny w zapytaniu. Do sprawdzenia typu pomocne nam będzie funkcja SQL_VARIANT_PROPERTY. Przykład wykorzystania takiej funkcji jest poniżej:
select SQL_VARIANT_PROPERTY(POWER(CAST (2 as bigint), 2) , 'BaseType')​
Kiedy dodamy kastowanie do bigint to możemy już uzyskiwać większe liczby.
with Hanoi_cte   AS 
(
select 
CAST (1 AS bigint) as n,
CAST (1 AS bigint) as counts

union all

select 
n + 1   as n 
,POWER(CAST (2 as bigint), n+1) -1 as counts
from Hanoi_cte 
where counts < CAST(0x3FFFFFFFFFFFFFFF AS bigint)
)
select * from Hanoi_cte  

Ale i tak dla tego problemu możemy iterować do 63 rekordu - czy wiesz może dlaczego :)
Tak samo dodałem kastowanie do bigint dla problemu fibonacciego:
WITH Fibonacci_cte  AS
(
     SELECT 
CAST (0 as bigint) as PrevFibN, 
CAST(1 as bigint) as FibN, 
1 as Nr

     UNION ALL

     SELECT 
FibN, 
PrevFibN +FibN, 
Nr+1 
     FROM Fibonacci_cte
     WHERE Nr < 92 
)
select * from Fibonacci_cte
A wyniki tego zapytania są poniżej:

Brak komentarzy:

Prześlij komentarz