La génération d’une séquence modifie le comportement sur un numéro de ligne spécifique

la programmation


Passer un moment dense/senior aujourd’hui…

J’ai une requête SQL (héritée) exécutée sur un cte qui produit désormais des lignes numérotées de 1 à 16384. Je m’attends à ce qu’elle génère des lettres de colonne dans la plage “A” à “XFC” (générée précédemment “A” à “ZZ “)

Cela devrait fonctionner

SQL
SELECT l, CASE WHEN l >= 703 THEN Char(65 + (l - 703) / 702 % 702) ELSE '' END 
			+ CASE WHEN l >=27 then Char(65 + (l - 27) / 26 % 26) ELSE '' END
			+ Char(65 + (l  - 1) % 26)
FROM eFinal
WHERE l < 16384
ORDER BY l;

En fait, il fait travail – JUSQU’À ce que nous arrivions à la ligne 6787 – au lieu de renvoyer “JAA”, il revient à “IAA” (jusqu’à “IAZ” et à partir de là, il fait des choses étranges et merveilleuses (y compris des caractères non-ascii))

Je peux le contourner avec

SQL
SELECT l, (CASE WHEN l >= 6787 THEN Char((65 + (l - 703) / 702 % 702) + 1) 
				WHEN l >= 703 THEN  Char(65 + (l - 703) / 702 % 702) ELSE '' END)
		+ (CASE WHEN l > 27 THEN (Char(65 + (l - 27) / 26 % 26)) ELSE '' END)
			+(Char(65 + (l  - 1) % 26))
FROM eFinal
WHERE l < 16384
ORDER BY l;

Ce qui fonctionne jusqu’à “XFC”.

Ce que je ne comprends pas, c’est… pourquoi ?

J’ai du mal à comprendre la signification de 6786 en tant que nombre clé – même si j’ai été surexcité lorsque j’ai réalisé qu’il s’agissait de 26 x 255, mais l est-ce qu’un bigint n’est pas pertinent ?

Ce que j’ai essayé :

Code complet pour reproduire le comportement

SQL
;with 
 cte1 AS (select n from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1) ) AS X(n))
,cte2 AS (SELECT a.n FROM cte1 a CROSS JOIN cte1 b)	-- 10*10
,cte3 AS (SELECT a.n FROM cte1 a CROSS JOIN cte2 b)	-- 10*100
,cte4 AS (SELECT a.n FROM cte2 a CROSS JOIN cte3 b )	-- 1000*100
,eFinal AS (SELECT l = ROW_NUMBER() OVER (ORDER BY a.n) FROM cte2 a CROSS JOIN cte3 b )
SELECT l, CASE WHEN l >= 703 THEN Char(65 + (l - 703) / 702 % 702) ELSE '' END 
			+ CASE WHEN l >=27 then Char(65 + (l - 27) / 26 % 26) ELSE '' END
			+ Char(65 + (l  - 1) % 26)
FROM eFinal
--WHERE l < 16384
where l BETWEEN 6780 AND 6790
ORDER BY l;

Solution 1

Parce que ton calcul est faux ! 😀

SQL
DECLARE @cnt INT = 6785; 
WHILE @cnt < 6789 
BEGIN 
	SELECT @cnt
	     , (@cnt - 27) / (26 * 26)
		 , CASE WHEN (@cnt - 27 / (26 * 26)) > 0 THEN CHAR(65 + ((@cnt - 27) / (26 * 26))) ELSE '' END
		 , Char(65 + (@cnt - 27) / 26 % 26)
		 , Char(65 + (@cnt  - 1) % 26)
	SET @cnt = @cnt + 1;
END

コメント

タイトルとURLをコピーしました