Un "quine" en SQL (self-reproducing SQL)

Un quine en informatique est un programme (une sorte de métaprogramme) dont la sortie et le code source sont identiques. À titre de défi ou d'amusement, certains programmeurs essaient d'écrire le plus court quine dans un langage donné.

Voici mes exemples en Transact SQL et ANSI SQL (la plus petite est dans exemple 5)

Notez que on ne tient pas en compte le format des colonnes retournées dont le client SQL applique selon les paramètres de sortie console. Par exemple, il est possible de n'est pas afficher les en-têtes de colonnes tout à fait.

Exemple 1. Transact SQL

Transact SQL basé sur l'instruction PRINT. En fait, PRINT c'est RAISERROR dont le sévérité est 0.

DECLARE @c varchar(255), @b varchar(255), @d char(1)
SELECT @d = ''''
SELECT @b = 'DECLARE @c varchar(255), @b varchar(255), @d char(1)
SELECT @d = '
SELECT @c = 'PRINT @b + @d + @d + @d + @d
PRINT substring(@b, 55, 7) + substring(@c, 7, 2) + substring(@b, 64, 3) + @d + @b + @d
PRINT substring(@b, 55, 7) + substring(@b, 9, 2) + substring(@b, 64, 3) + @d + @c + @d
PRINT @c'
PRINT @b + @d + @d + @d + @d
PRINT substring(@b, 55, 7) + substring(@c, 7, 2) + substring(@b, 64, 3) + @d + @b + @d
PRINT substring(@b, 55, 7) + substring(@b, 9, 2) + substring(@b, 64, 3) + @d + @c + @d
PRINT @c

Exemple 2. Transact SQL

Transact SQL sans les instructions de sortie. Par contre, l'ordre dans l'union (UNION) n'est pas défini en cas commun donc il faut utiliser UNION ALL ou rajouter ORDER BY.

DECLARE @c varchar(255), @b varchar(255), @d char(1)
SELECT @d = ''''
SELECT @b = 'DECLARE @c varchar(255), @b varchar(255), @d char(1)
SELECT @d = '
SELECT @c = 'SELECT @b + @d + @d + @d + @d
UNION ALL SELECT substring(@b, 55, 7) + substring(@c, 8, 2) + substring(@b, 64, 3) + @d + @b + @d
UNION ALL SELECT substring(@b, 55, 7) + substring(@b, 9, 2) + substring(@b, 64, 3) + @d + @c + @d
UNION ALL SELECT @c'
SELECT @b + @d + @d + @d + @d
UNION ALL SELECT substring(@b, 55, 7) + substring(@c, 8, 2) + substring(@b, 64, 3) + @d + @b + @d
UNION ALL SELECT substring(@b, 55, 7) + substring(@b, 9, 2) + substring(@b, 64, 3) + @d + @c + @d
UNION ALL SELECT @c

Exemple 3. Transact SQL

La même solution mais avec une seule instruction SELECT

DECLARE @c varchar(512), @b varchar(512), @d char(1)
SELECT @d = ''''
SELECT @b = 'DECLARE @c varchar(512), @b varchar(512), @d char(1)
SELECT @d = '
SELECT @c = 'SELECT @b + @d + @d + @d + @d + char(13) + char(10) +
substring(@b, 55, 7) + substring(@c, 8, 2) + substring(@b, 64, 3) + @d + @b + @d + char(13) + char(10) +
substring(@b, 55, 7) + substring(@b, 9, 2) + substring(@b, 64, 3) + @d + @c + @d + char(13) + char(10) +
@c'
SELECT @b + @d + @d + @d + @d + char(13) + char(10) +
substring(@b, 55, 7) + substring(@c, 8, 2) + substring(@b, 64, 3) + @d + @b + @d  + char(13) + char(10) +
substring(@b, 55, 7) + substring(@b, 9, 2) + substring(@b, 64, 3) + @d + @c + @d + char(13) + char(10) +
@c

Exemple 4. ANSI SQL

La fonction SUNSTRING appartient le standard SQL 99 (ou 2003 ? A vérifier...), donc elle est implémentée par la majorité de SGBD mais elle peut avoir le nom un peut diffèrent, comme SUBSTR en Oracle.

SELECT substring(S.v, 2, 7) + A.v + substring(S.v, 1, 8) + C.v + A.v + C.v + 
substring(S.v, 22, 4) + substring(S.v, 20, 2) + substring(S.v, 22, 4) + substring(S.v, 23, 1) + char(13) + char(10) +
substring(S.v, 9, 11) + substring(S.v, 1, 8) + C.v + S.v + C.v + substring(S.v, 22, 4) + 
substring(S.v, 20, 2) + substring(S.v, 22, 4) + substring(S.v, 24, 1) + char(13) + char(10) +
substring(S.v, 9, 11) + substring(S.v, 1, 8) + C.v + C.v + C.v + C.v + substring(S.v, 22, 4) + 
substring(S.v, 20, 2) + substring(S.v, 22, 4) + substring(S.v, 6, 1)
FROM
(SELECT 'substring(S.v, 2, 7) + A.v + substring(S.v, 1, 8) + C.v + A.v + C.v + 
substring(S.v, 22, 4) + substring(S.v, 20, 2) + substring(S.v, 22, 4) + substring(S.v, 23, 1) + char(13) + char(10) +
substring(S.v, 9, 11) + substring(S.v, 1, 8) + C.v + S.v + C.v + substring(S.v, 22, 4) + 
substring(S.v, 20, 2) + substring(S.v, 22, 4) + substring(S.v, 24, 1) + char(13) + char(10) +
substring(S.v, 9, 11) + substring(S.v, 1, 8) + C.v + C.v + C.v + C.v + substring(S.v, 22, 4) + 
substring(S.v, 20, 2) + substring(S.v, 22, 4) + substring(S.v, 6, 1)
FROM
' AS v) AS A
CROSS JOIN (SELECT '(SELECT CROSS JOIN v) AS ' AS v) AS S
CROSS JOIN (SELECT '''' AS v) AS C

Exemple 5. ANSI SQL

La plus petite instruction que j'ai réussi à faire. Voulez vous le réduire encore plus ?

SELECT left(A.v, 81) + char(39) + A.v + char(39) + right(A.v, 11)
FROM (SELECT 'SELECT left(A.v, 81) + char(39) + A.v + char(39) + right(A.v, 11) 
FROM (SELECT AS v) AS A' AS v) AS A

P.S. Si vous utilisez SQL Server Management Studio, vérifiez que l'option de sortie permet voir les chaines de caractères assez longues. Par défaut la longueur maximale est 255 caractères et il faut donc l'agrandir à 2000.