Que dicas gerais você tem para jogar golfe no T-SQL? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos para o T-SQL. Poste uma dica por resposta.
Obrigado a Marcog pela ideia original. :)
Respostas:
Minha sacola geral de truques ::
@
é uma variável válida no t-sql.iif
uma declaração de caso no estilo VB. Isso é quase sempre mais curto que um equivalenteif
else
.\
é uma maneira útil de inicializar um número como 0 em um tipo de dinheiro. Você pode converter um valor em flutuante adicionandoe
. por exemplo,4e
ou\k
que definirá k como o valor 0,00 dinheiro.rCTE
parece ser a melhor maneira de criar uma tabela numérica com menos de 100 entradas. Ainda mais curto do que usar spt_values. Se você precisar de mais de 100, junte-se a cruz e adicione-os.+=
e outros operadores compostos foram adicionados em 2008. Use-os para salvar alguns caracteres.;
.Select*from A,B where condition
é mais curto queselect*from A join b on condition
goto
loop de estilo do while.STR()
é a função mais curta para transformar um int em uma string. Se você estiver fazendo mais de uma conversão ou precisar concatinar vários tipos de dados diferentes, considere aconcat
função Por exemplo,'hello'+str(@)
é mais curto queconcat('hello',@)
, mashello+str(@)+str(@a)
é mais longo queconcat('hello',@,@a)
Por exemplo, esses dois são semanticamente equivalentes.
Você pode usar
Values
para criar uma tabela ou subconsulta. Isso só será realmente um benefício se você precisar de algumas linhas constantes.fonte
Compactação de código usando SQL
O SQL é prolixo, tem pontuações altas e, tanto quanto nós os amamos,
SELECT FROM WHERE
custa 23 bytes a cada uso. Você pode compactar essas e outras palavras repetidas ou trechos de código inteiros. Isso diminuirá o custo marginal do código repetido para 1 byte! *Como isso funciona:
O problema:
O custo inicial é próximo a 100 bytes e cada linha na tabela de substituição custa outros 6 bytes. Esse tipo de lógica não será muito eficaz, a menos que você esteja trabalhando com muito código que não pode reduzir ou o desafio é baseado em compactação.
Aqui está um exemplo
O desafio é obter os últimos 10 múltiplos de 2,3 e 5 até n. Digamos que essa ( 343 bytes de golfe ) seja a melhor solução que eu poderia encontrar:
Exemplo após o código ser compactado
Isso executa o mesmo código acima, é ~ 302 bytes jogados .
fonte
SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)
vez de usar uma única coluna comLEFT()
eSUBSTRING()
. Se você tiver 8 ou mais, evitar cotações e vírgulas extras é uma boa opção.SET @=REPLACE(REPLACE(REPLACE(...
Aqui está uma pergunta engraçada. Isso converterá os valores em uma coluna em uma única tupla.
EDIT: Obrigado pelos comentários. Parece que a maneira mais curta de acumular sem as tags XML é:
Nota: se XML for uma saída válida, você poderá omitir a seleção externa e parens. Também
column1+''
funciona apenas para strings. Para tipos de números, é melhor fazercolumn1+0
fonte
<column_name>value1</column_name><column_name>value2</column_name>...
. Para obter um CSV de uma coluna, você podeDECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @
(obrigado pela primeira dica de @ MichaelB) que retornarávalue1,value2,...
. No entanto, é na verdade 9 caracteres mais do que o seu truque XML :(Ltrim
não é necessário, pois select (select ... for xml path ('')) retorna umnvarchar(max)
. Além disso, para resolver o problema da coluna, basta usar uma expressão não mutante. Para números, você pode fazerv+0
, para string adicionar string vazia, etc. Embora eu realmente não considere isso uma dica de golfe, isso é apenas uma realidade de como escrever consultas no servidor sql.É possível usar alguns operadores bit a bit no T-SQL .
Não tenho um exemplo concreto, mas acredito que é um fato importante saber jogar golfe no T-SQL.
fonte
x=0 or y=0
, você pode escrever isso como o equivalente logicamentex|y=0
que economiza alguns bytes!Imprimir em vez de Selecionar
É simples assim! Então, aqui está um poliglota T-SQL / Python:
Experimente online
fonte
A notação científica é um método mais curto para expressar números muito grandes e muito pequenos, por exemplo,
select 1000000000
=select 1E9
eselect 0.000001
=select 1E-6
.fonte
Michael B mencionou o uso de um CTE recursivo para uma tabela numérica , mas não mostrou um exemplo. Aqui está uma versão do MS-SQL que elaboramos neste outro segmento :
Observe que você pode alterar o valor inicial (
1 n
), o intervalo (n + 1
) e o valor final (n < 99
).Se você precisar de mais de 100 linhas, precisará adicionar
option (maxrecursion 0)
:ou junte o rCTE a si mesmo:
Embora não seja garantido que este último retorne em ordem numérica sem um
ORDER BY 1
fonte
Use a compressão GZIP para seqüências muito longas!
Então, eu sabia que o SQL 2016 adicionou uma
COMPRESS
função (e umDECOMPRESS
função), que (finalmente) traz a capacidade de GZIP uma string ou binário.O problema é que não está claro imediatamente como tirar proveito disso para o golfe;
COMPRESS
pode pegar uma string, mas retorna aVARBINARY
, que é mais curto em bytes (quando armazenado em umVARBINARY
campo SQL ), mas é mais longo em caracteres (hexadecimal bruto).Já brinquei com isso antes, mas finalmente consegui montar uma versão funcional, com base nessa resposta antiga no SO . Essa publicação não usa as novas funções GZIP, mas converte um
VARBINARY
em uma string codificada em Base-64. Nós apenas precisamos inserir as novas funções no lugar certo e aprimorar um pouco.Aqui está o código que você pode usar para converter sua cadeia muito longa na cadeia compactada codificada em Base-64:
Pegue a saída e use-a no seu código no lugar da cadeia longa original, junto com:
Então, em vez do seu código original ( 1471 bytes )
você teria isso ( 1034 bytes ):
Veja esta resposta que me salvou quase 200 bytes.
Eu não fiz as contas, mas claramente devido à sobrecarga, isso só será eficaz para seqüências extremamente longas. Provavelmente existem outros lugares onde isso não pode ser usado; Eu já descobri que você precisa
SELECT
, você não podePRINT
, caso contrário você obtém:EDIT : Versão mais curta do código de descompactação, cortesia de @digscoop :
Salve 10 bytes alterando o externo
CAST
para uma conversão implícita usandoCONCAT
:Você também pode declarar uma variável do tipo em
XML
vez deVARCHAR(MAX)
e salvar no interiorCAST
:Isso é um pouco mais longo por si só, mas se você precisar dele em uma variável por outros motivos, poderá ajudar.
fonte
Algumas reflexões sobre a criação e o uso de tabelas para desafios:
1. A entrada SQL pode ser obtida através de uma tabela pré-existente
Código Golf Métodos de Entrada / Saída :
Criar e preencher esta tabela com valores de entrada não conta para o total de bytes, você pode apenas assumir que ele já está lá.
Isso significa que seus cálculos podem gerar via SELECT simples da tabela de entrada:
2. Se possível, não crie realmente uma tabela
Em vez de (69 bytes):
Basta fazer (43 bytes):
3. Se possível, crie a tabela com um SELECT INTO
Em vez de (39 bytes):
Faça isso (17 bytes):
4: considere juntar várias colunas
Aqui estão duas variações que retornam a mesma saída:
Após alguns testes, a versão superior (várias colunas) parece mais curta com 7 ou menos linhas , a versão inferior (devido a ESQUERDA e SUBSTRING) é mais curta com 8 ou mais linhas . Sua milhagem pode variar, dependendo dos dados exatos.
5: Use REPLACE e EXEC para sequências muito longas de texto
Na veia da excelente resposta de Drei , se você tiver 15 ou mais valores , use
REPLACE
um símbolo para se livrar da repetição'),('
separadores entre os elementos:114 caracteres:
112 caracteres:
Se você já é usando SQL dinâmico por outros motivos (ou tiver várias substituições), o limite em que vale a pena é muito menor.
6: Use um SELECT com colunas nomeadas em vez de um monte de variáveis
Inspirado pela excelente resposta do jmlt aqui , reutilize as strings através de um SELECT:
retorna
(Para o MS SQL I mudou o
\t
para um regresso em-linha, e mudadoCONCAT()
para+
salvar bytes).fonte
Marque seu código para destacar a sintaxe T-SQL
Em vez de apenas:
Inclua uma tag de idioma como esta:
e o resultado será:
fonte
Aproveite os novos recursos / funções do MS SQL 2016 e SQL 2017
Se você não possui cópias locais para trabalhar, pode jogar online com o StackExchange Data Explorer (SQL 2016) ou com dbfiddle.uk (SQL 2016 ou SQL "vNext").
STRING_SPLIT ( SQL 2016 e posterior )
Se você precisar criar um alias na tabela ou consultar o nome da coluna:
TRIM ( SQL 2017 ou posterior )
Mais curto que
RTRIM()
e certamente menor queLTRIM(RTRIM())
.Também tem uma opção para remover outros caracteres ou conjuntos de caracteres do começo ou do fim:
retorna
L Server 2
TRADUZIR ( SQL 2017 ou posterior )
TRANSLATE
permite substituir vários caracteres em uma etapa, em vez de váriasREPLACE
instruções aninhadas . Mas não comemoram muito muito, ele só substitui caracteres únicos individuais com diferentes personagens individuais.Cada caractere na segunda cadeia é substituído pelo caractere correspondente na terceira cadeia.
Parece que poderíamos eliminar um monte de personagens com algo como
REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')
Alguns mais interessantes também, como
CONCAT_WS
eSTRING_AGG
que provavelmente valem uma olhada também.fonte
Vaca sagrada, eu descobri a maravilha de
PARSENAME
( SQL 2012 ou superior ).A função foi criada para isolar as partes de um nome de objeto
servername.dbname.dbo.tablename
, mas funciona para quaisquer valores separados por pontos. Lembre-se de que conta da direita , não da esquerda:Se você tiver menos de 4 valores separados por pontos, ele retornará
NULL
para o restante (mas ainda conta da direita para a esquerda ):Aqui é onde entra a mágica: combine-a com
STRING_SPLIT
(2016 ou superior) para criar tabelas com várias colunas na memória !!Velho e preso:
Nova gostosura:
Claramente, suas economias reais dependem do tamanho e do conteúdo da tabela e de como exatamente você a está usando.
Observe que, se seus campos são de largura constante, é melhor usar
LEFT
eRIGHT
separá-los em vez dePARSENAME
(não apenas porque os nomes das funções são mais curtos, mas também porque você pode eliminar completamente os separadores).fonte
Mais alguns truques não relacionados que vi e quis preservar:
GO #
para repetir um bloco um número específico de vezes .Vi esse truque inteligente na excelente resposta de Paulo .
Obviamente, isso redefiniria quaisquer variáveis de contador no bloco, portanto você teria que pesar isso em um
WHILE
loop oux: ... GOTO x
loop.SELECT TOP ... FROM systypes
Da mesma pergunta que a de Paulo acima, Anuj Tripathi usou o seguinte truque :
ou, como sugerido por pinkfloydx33 nos comentários:
Note que este não depende de qualquer um dos atuais conteúdos de
systypes
, apenas que existe a visão do sistema (o que faz em cada banco de dados MS SQL), e contém pelo menos 10 linhas (parece conter 34, para a maioria das versões recentes do SQL ) Não consegui encontrar nenhuma visualização do sistema com nomes mais curtos (que não exigiam umsys.
prefixo), portanto isso pode ser o ideal.fonte
Veja esta pergunta em dba.stackexchange para obter algumas idéias interessantes para adicionar uma coluna numérica a um resultado STRING_SPLIT.
Dada uma string como
'one,two,three,four,five'
, queremos obter algo como:De acordo com a resposta de Joe Obbish, use
ROW_NUMBER()
e encomende porNULL
ou uma constante:De acordo com a resposta de Paul White, use um
SEQUENCE
:Sequências são objetos persistentes interessantes; você pode definir o tipo de dados, o valor mínimo e o máximo, o intervalo e se ele envolve o início:
De acordo com a resposta de Joseph Biju, você pode usar a
IDENTITY()
função (que não é a mesma que aIDENTITY
propriedade em conjunto com um INSERT:Observe que os dois últimos parâmetros em
IDENTITY(INT,1,1)
são opcionais e, por padrão, serão 1 se excluídos.fonte
ORDER BY
se puder me safar (veja minha resposta a Toasty, Burnt, Brulee , por exemplo).Acabei de descobrir que você pode usar números para um único caractere
REPLACE
para eliminar aspas :Isto é porque
REPLACE
uma conversão implícita em string.Ambos produzem a mesma saída:
fonte
_ e # são aliases válidos. Eu os uso com o CROSS APPLY para fazer com que apareçam as colunas retornadas que fazem parte da cláusula FROM, por exemplo
Eu gosto disso quando o único objetivo do CROSS APPLY é calcular uma expressão.
Nesse caso, usar o APPLY para calcular subexpressões é uma maneira interessante de tornar seu código mais seco (e mais curto). Pelo que vi nos planos de execução, não há custo adicional para essa abordagem. O compilador descobre que você está apenas computando algo e o trata como qualquer outra expressão.
fonte