Dziś pokażę, jak można rozwiązać zagadkę o gwoździach Wilsona za pomocą SQL-a.
Rozwiązanie nadesłał jeden z Czytelników. Pozwoliłem sobie nieco sformatować i uporządkować kod, jednak ogólną logikę rozwiązania pozostawiłem bez zmian.
Kod wygląda tak:
;
WITH licz10
AS ( SELECT 0 x
UNION ALL
SELECT licz10.x + 1
FROM licz10
WHERE licz10.x < 9 ) ,
licz
AS ( SELECT l1.x + 10 * l2.x + 100 * l3.x x
FROM licz10 l1
, licz10 l2
, licz10 l3
WHERE l1.x + 10 * l2.x + 100 * l3.x <= 1000) ,
cte
AS ( SELECT 6 * m.x + 9 * s.x + 20 * d.x suma
, d.x d
, s.x s
, m.x m
FROM licz m
, licz s
, licz d
WHERE s.x <= 1
AND d.x <= 2) ,
cte2
AS ( SELECT *
, CASE WHEN cte.suma - 1 <> LAG(cte.suma) OVER ( ORDER BY cte.suma ) THEN 1
ELSE 0
END * CASE WHEN cte.suma = LAG(cte.suma) OVER ( ORDER BY cte.suma ) THEN 0
ELSE 1
END kandydat
FROM cte)
SELECT cte2.suma - 1 AS suma
FROM cte2
GROUP BY cte2.suma
HAVING MAX(kandydat) > 0;
Wyniki:
suma
5
8
11
14
17
19
23
25
28
31
34
37
43
6000
6006
6009
6012
6015
6018
6021
6024
6027
6030
6033
6036
6042
Jak widać ostatni "nieduży" kandydat pojawia się przy 43, potem długo, długo nic, wreszcie kolejne "dziury" mamy przy sześciu tysiącach.
Czemu tak?
Otóż SQL to nie jest język analityczny, matematyczny, tylko proste głupiątko do żonglowania danymi. Jeżeli ograniczymy ilość szóstek, dziewiątek i dwudziestek, to siłą rzeczy niektóre kombinacje wymagające większych ich ilości nie zostaną znalezione i skrypt "wypluje" je jako kandydatury na wynik. Ale - jak się łatwo domyśleć - zwiększając limit z 1000 na, dajmy na to, 2000, zobaczymy, że te "dziury" w okolicach 6000 są tylko tymczasowe. I podobnie jak w jednym z poprzednich przykładów, gdzie losowaliśmy sobie gwoździe w Excelu, tak i tutaj widać wyraźnie, że zwiększanie limitu ciągle "zakleja" duże dziury, pozostawiając 43 nietknięte.
Jeżeli chcesz do komentarza wstawić kod, użyj składni:
[code]
tutaj wstaw swój kod
[/code]
Jeżeli zrobisz literówkę lub zmienisz zdanie, możesz edytować komentarz po jego zatwierdzeniu.