¿Qué consejos generales tienes para jugar al golf en T-SQL? Estoy buscando ideas que se puedan aplicar a los problemas de golf de código en general que sean al menos algo específicos para T-SQL. Por favor, publique un consejo por respuesta.
Gracias a Marcog por la idea original. :)
Respuestas:
Mi bolsa general de trucos ::
@
es una variable válida en t-sql.iif
una declaración de caso de estilo VB. Esto es casi siempre más corto que un equivalenteif
else
.\
es una forma útil de inicializar un número como 0 en un tipo de dinero. Puede convertir un valor en un flotante agregandoe
. por ejemplo,4e
o\k
que establecerá k en el valor 0.00 dinero.rCTE
parece ser la mejor manera de crear una tabla de números de menos de 100 entradas. Incluso más corto que usar spt_values. Si necesita más de un 100, cruce y agregue.+=
y otros operadores compuestos se agregaron en 2008. Úselos para guardar algunos caracteres.;
.Select*from A,B where condition
es más corto queselect*from A join b on condition
goto
bucle de estilo do- while.STR()
es la función más corta para convertir un int en una cadena. Si está realizando más de una conversión o puede necesitar concatenar numerosos tipos de datos diferentes, considere laconcat
función. Por ejemplo,'hello'+str(@)
es más corto queconcat('hello',@)
, perohello+str(@)+str(@a)
es más largo queconcat('hello',@,@a)
Por ejemplo, estos dos son semánticamente equivalentes.
Puede usar
Values
para crear una tabla o subconsulta. Esto solo será realmente un beneficio si necesita algunas filas constantes.fuente
Compresión de código usando SQL
SQL es prolijo, tiene puntajes altos y, por mucho que los amemos,
SELECT FROM WHERE
cuesta 23 bytes con cada uso. Puede comprimir estas y otras palabras repetidas o fragmentos de código completos. ¡Hacer esto disminuirá el costo marginal del código repetido a 1 byte! *Cómo funciona esto:
El problema:
El costo inicial es cercano a 100 bytes y cada fila en la tabla de reemplazo cuesta otros 6 bytes. Este tipo de lógica no será muy efectiva a menos que esté trabajando con un montón de código que no puede recortar o que el desafío esté basado en la compresión.
Aquí hay un ejemplo
El desafío es obtener los últimos 10 múltiplos de 2,3 y 5 que conducen a n. Digamos que esto ( 343 bytes golfed ) es la mejor solución que se me ocurrió:
Ejemplo después de comprimir el código
Esto ejecuta el mismo código que el anterior, tiene ~ 302 bytes de golf .
fuente
SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)
lugar de usar una sola columna conLEFT()
ySUBSTRING()
. Si tiene 8 o más, entonces evitar las comillas y comillas adicionales es una buena compensación.SET @=REPLACE(REPLACE(REPLACE(...
Aquí hay uno divertido. Esto convertirá los valores en una columna en una sola tupla.
EDITAR: Gracias por los comentarios. Parece que la forma más corta de enrollar sin las etiquetas XML es:
Nota: si XML es una salida válida, puede omitir la selección externa y los parens. Además
column1+''
, solo funciona para cadenas. Para los tipos de números, es mejor hacerlocolumn1+0
fuente
<column_name>value1</column_name><column_name>value2</column_name>...
. Para tener un CSV de una columna, puedeDECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @
(gracias por el primer consejo de @ MichaelB) que volverávalue1,value2,...
. Sin embargo, en realidad es 9 caracteres más largo que tu truco XML :(Ltrim
no es necesario ya que select (select ... for xml path ('')) devuelve unnvarchar(max)
. Además, para resolver el asunto de la columna, simplemente use una expresión no mutante. Para los números que puede hacerv+0
, para la cadena agregue una cadena vacía, etc. Aunque realmente no considero que esto sea un consejo de golf, es una triste realidad de cómo escribir consultas en el servidor SQL.Es posible usar algunos operadores bit a bit en T-SQL .
No tengo un ejemplo concreto, pero creo que es bueno saberlo cuando se juega golf en T-SQL.
fuente
x=0 or y=0
, puede escribir eso como el equivalente lógicox|y=0
que ahorra bastantes bytes!Imprimir en lugar de Seleccionar
¡Es tan simple como eso! Así que aquí hay un políglota T-SQL / Python:
Pruébalo en línea
fuente
La notación científica es un método más corto para expresar números muy grandes y muy pequeños, por ejemplo,
select 1000000000
=select 1E9
yselect 0.000001
=select 1E-6
.fuente
Michael B mencionó el uso de un CTE recursivo para una tabla numérica , pero no mostró un ejemplo. Aquí hay una versión de MS-SQL que elaboramos en este otro hilo :
Tenga en cuenta que puede cambiar el valor inicial (
1 n
), el intervalo (n + 1
) y el valor final (n < 99
).Sin embargo, si necesita más de 100 filas, deberá agregar
option (maxrecursion 0)
:o unirse a la rCTE a sí mismo:
Aunque no se garantiza que este último regrese en orden numérico sin un
ORDER BY 1
fuente
Utilice la compresión GZIP para cadenas muy largas.
Entonces sabía que SQL 2016 agregó una
COMPRESS
función (y unaDECOMPRESS
función), que (finalmente) brinda la capacidad de GZIP una cadena o binario.El problema es que no está claro de inmediato cómo aprovechar esto para jugar al golf;
COMPRESS
puede tomar una cadena pero devuelve unVARBINARY
, que es más corto en bytes (cuando se almacena en unVARBINARY
campo SQL ), pero es más largo en caracteres (hexadecimal).He jugado con esto antes, pero finalmente pude armar una versión funcional, basada en esta vieja respuesta en SO . Esa publicación no usa las nuevas funciones GZIP, pero convierte una
VARBINARY
cadena codificada en Base-64. Solo necesitábamos insertar las nuevas funciones en el lugar correcto y desarrollarlas un poco.Aquí está el código que puede usar para convertir su cadena muy larga a la cadena comprimida codificada Base-64:
Tome la salida y úsela en su código en lugar de la cadena larga original, junto con:
Entonces, en lugar de su código original ( 1471 bytes )
tendrías esto ( 1034 bytes ):
Vea esta respuesta que me ahorró casi 200 bytes.
No he hecho los cálculos, pero claramente debido a la sobrecarga, esto solo será efectivo para cadenas extremadamente largas. Probablemente hay otros lugares que no se pueden usar; Ya descubrí que tienes que
SELECT
hacerlo, no puedesPRINT
, de lo contrario obtienes:EDITAR : versión más corta del código de descompresión, cortesía de @digscoop :
Ahorre 10 bytes cambiando el exterior
CAST
a una conversión implícita usandoCONCAT
:También puede declarar una variable de tipo en
XML
lugar deVARCHAR(MAX)
y guardar en el interiorCAST
:Esto es un poco más largo por sí solo, pero si lo necesita en una variable por otros motivos, entonces podría ayudar.
fuente
Algunas reflexiones sobre la creación y el uso de tablas para desafíos:
1. La entrada SQL se puede tomar a través de una tabla preexistente
Métodos de entrada / salida de golf de código :
Crear y completar esta tabla con valores de entrada no cuenta para el total de bytes, solo puede suponer que ya está allí.
Esto significa que sus cálculos pueden salir a través de SELECT simple desde la tabla de entrada:
2. Si es posible, en realidad no cree una tabla
En lugar de (69 bytes):
Solo haz (43 bytes):
3. Si es posible, cree la tabla con un SELECCIONAR EN
En lugar de (39 bytes):
Haga esto (17 bytes):
4: Considere mezclar varias columnas juntas
Aquí hay dos variaciones que devuelven el mismo resultado:
Después de algunas pruebas, la versión superior (columnas múltiples) parece más corta con 7 o menos filas , la versión inferior (debido a la IZQUIERDA y SUBSTRING) es más corta con 8 o más filas . Su kilometraje puede variar, dependiendo de sus datos exactos.
5: Use REPLACE y EXEC para secuencias de texto muy largas
En la línea de la excelente respuesta de cómodamentedrei , si tiene 15 o más valores , use
REPLACE
un símbolo para deshacerse de los'),('
separadores repetidos entre elementos:114 caracteres:
112 caracteres:
Si usted está ya utilizando SQL dinámico por otras razones (o tener múltiples sustituye), entonces el umbral en el que esto vale la pena es mucho menor.
6: Use un SELECT con columnas con nombre en lugar de un montón de variables
Inspirado por la excelente respuesta de jmlt aquí , reutilice las cadenas a través de un SELECCIONAR:
devoluciones
(Para MS SQL, cambié
\t
a un retorno en línea y cambiéCONCAT()
a+
para guardar bytes).fuente
Etiquete su código para resaltar la sintaxis de T-SQL
En lugar de solo:
Incluya una etiqueta de idioma como esta:
y el resultado será:
fuente
Aproveche las nuevas características / funciones en MS SQL 2016 y SQL 2017
Si no tiene copias locales para trabajar, puede jugar en línea con el Explorador de datos de StackExchange (SQL 2016) o con dbfiddle.uk (SQL 2016 o SQL "vNext").
STRING_SPLIT ( SQL 2016 y posterior )
Si necesita alias de la tabla o hacer referencia al nombre de la columna:
TRIM ( SQL 2017 o posterior )
Más corto que
RTRIM()
y ciertamente más corto queLTRIM(RTRIM())
.También tiene una opción para eliminar otros caracteres o conjuntos de caracteres desde el principio o el final:
devoluciones
L Server 2
TRADUCIR ( SQL 2017 o posterior )
TRANSLATE
le permite reemplazar varios caracteres en un solo paso, en lugar de un conjunto deREPLACE
declaraciones anidadas . Pero no celebre demasiado , solo reemplaza caracteres individuales individuales con caracteres individuales diferentes.Cada carácter en la segunda cadena se reemplaza por el carácter correspondiente en la tercera cadena.
Parece que podríamos eliminar un montón de personajes con algo como
REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')
Algunos más interesantes también, como
CONCAT_WS
ySTRING_AGG
que probablemente valen la pena también.fuente
Santa vaca, he descubierto la maravilla de
PARSENAME
( SQL 2012 o superior ).La función se creó para aislar las partes de un nombre de objeto como
servername.dbname.dbo.tablename
, pero funciona para cualquier valor separado por puntos. Solo recuerda que cuenta desde la derecha , no desde la izquierda:Si tiene menos de 4 valores separados por puntos, devolverá
NULL
el resto (pero aún cuenta de derecha a izquierda ):Sin embargo, aquí es donde entra la magia: ¡combínelo con
STRING_SPLIT
(2016 o superior) para hacer tablas en varias columnas en memoria!Viejo y roto:
Nuevo calor:
Claramente, sus ahorros reales dependen del tamaño y el contenido de la tabla, y de cómo lo está utilizando exactamente.
Tenga en cuenta que si sus campos son de ancho constante, probablemente sea mejor usarlos
LEFT
yRIGHT
separarlos en lugar dePARSENAME
(no solo porque los nombres de las funciones son más cortos, sino también porque puede eliminar los separadores por completo).fuente
Un par de trucos más no relacionados que vi y quise preservar:
GO #
para repetir un bloque un número específico de veces .Vi este ingenioso truco en la excelente respuesta de Paul .
Esto, por supuesto, restablecería cualquier variable de contador en el bloque, por lo que tendría que comparar esto con un
WHILE
bucle o unx: ... GOTO x
bucle.SELECT TOP ... FROM systypes
De la misma pregunta que la anterior de Pablo, Anuj Tripathi usó el siguiente truco :
o, como lo sugiere pinkfloydx33 en los comentarios:
Tenga en cuenta que esto no se basa en ninguno de los contenidos reales de
systypes
, solo que la vista del sistema existe (que existe en todas las bases de datos MS SQL) y contiene al menos 10 filas (parece contener 34, para las versiones más recientes de SQL ) No pude encontrar ninguna vista del sistema con nombres más cortos (que no requirieran unsys.
prefijo), por lo que esto puede ser ideal.fuente
Ver esta pregunta en dba.stackexchange para obtener algunas ideas interesantes para agregar una columna numérica a un resultado de STRING_SPLIT.
Dada una cadena como
'one,two,three,four,five'
, queremos obtener algo como:Según la respuesta de Joe Obbish, use
ROW_NUMBER()
y ordene porNULL
o una constante:Según la respuesta de Paul White, use un
SEQUENCE
:Las secuencias son interesantes objetos persistentes; puede definir el tipo de datos, el valor mínimo y máximo, el intervalo y si se ajusta al principio:
Según la respuesta de Biju jose, puede usar la
IDENTITY()
función (que no es lo mismo que laIDENTITY
propiedad junto con un INSERT:Tenga en cuenta que los dos últimos parámetros en
IDENTITY(INT,1,1)
son opcionales y su valor predeterminado será 1 si se excluye.fuente
ORDER BY
si puedo salirse con la suya (vea mi respuesta a Toasty, Burnt, Brulee , por ejemplo).Acabo de descubrir que puedes usar números para un solo carácter
REPLACE
para eliminar comillas :Esto es porque
REPLACE
hace una conversión implícita a cadena.Ambos producen la misma salida:
fuente
_ y # son alias válidos. Los uso con CROSS APPLY para que parezca que las columnas que devuelve son parte de la cláusula FROM, por ejemplo
Me gusta cuando el único propósito de CROSS APPLY es calcular una expresión.
Para el caso, usar APPLY para calcular subexpresiones es una buena manera de hacer que su código sea SECO (y más corto). Por lo que he visto en los planes de ejecución, este enfoque no tiene un costo adicional. El compilador se da cuenta de que solo estás calculando algo y lo trata como cualquier otra expresión.
fuente