fredag, november 11, 2011

TSQL Challenge 51

Ibland känns det kul att göra något mer eller mindre opassande för att testa hur långt åt fel håll man kan driva tekniken. I det här fallet var utmaningen att bygga en parser för binär representation av decimaltal, lösningen skulle bestå av endast en query vilket helt utesluter någon form av imperativ for loop. I Microsofts SQL dialekt har man istället tillgång till något som kallas CTE eller common table expression som låter en arbeta rekursivt med ett bassteg som bearbetar det första tecknet som följs av ett steg för n + 1 och i det här fallet slutligen ett steg som springer igenom alla resultat och multiplicerar med 2 (binärt). Sedan kan man summera resultatet för att få ut decimaltalet. Ett möjligt problem man kan springa på här är att ett exempeltal i pusslet är 36000000000000000001 vilket inte går att räkna fram med POW funktionen, annars kunde man använt den. Nu får man istället kvadrera själv vilket är lite roligare men ganska mycket bökigare.

  • Beskrivning av pusslet hos Beyond Relational - TC51
;WITH parse (Seq, Calc, Pow, DecimalValue, BinaryStringToBeParsed, Step)
AS
(
 SELECT
 Seq
 , CONVERT(INT,1)
 , CONVERT(INT,0)
 , CONVERT(DECIMAL(38,0),RIGHT(BinaryValue,1))
 , LEFT(BinaryValue, LEN(BinaryValue) - 1)
 , 'A'
 FROM TC51

 UNION ALL
 
 SELECT
 Seq
 , Calc + 1
 , Pow + 1
 , CONVERT(INT,RIGHT(BinaryStringToBeParsed,1))
 , LEFT(BinaryStringToBeParsed, LEN(BinaryStringToBeParsed) - 1)
 , 'B'
 FROM parse
 WHERE LEN(BinaryStringToBeParsed) > 0
 
 UNION ALL
 
 SELECT
 Seq
 , Calc
 , Pow - 1
 , CONVERT(DECIMAL(38,0),(2 * DecimalValue))
 , ''
 , 'C'
 FROM parse
 WHERE Pow > 0
)
SELECT
Seq
, sum(DecimalValue) [DecimalValue]
FROM parse
WHERE Pow = 0
GROUP BY Seq
ORDER BY SUM(DecimalValue), Seq
OPTION (MAXRECURSION 200)

Inga kommentarer: