Conseils pour jouer au golf dans T-SQL

16

Quels conseils généraux avez-vous pour jouer au golf dans T-SQL? Je cherche des idées qui peuvent être appliquées aux problèmes de golf de code en général qui sont au moins quelque peu spécifiques à T-SQL. Veuillez poster un pourboire par réponse.

Merci à Marcog pour l'idée originale. :)

Michael B
la source
un conseil - utilisez une langue différente pour jouer au golf. Les réponses SQL reçoivent généralement très peu ou pas de votes positifs.
t-clausen.dk

Réponses:

16

Mon sac général de trucs ::

  • @ est une variable valide en t-sql.
  • T-sql 2012 a ajouté iifune déclaration de cas de style VB. C'est presque toujours plus court qu'un équivalent if else.
  • \est un moyen utile pour initialiser un nombre à 0 dans un type monétaire. Vous pouvez convertir une valeur en un flottant en ajoutant e. par exemple 4eou \kqui mettra k à la valeur 0,00 argent.
  • rCTEsemblent être le meilleur moyen de créer une table numérique de moins de 100 entrées. Encore plus court que d'utiliser spt_values. Si vous avez besoin de plus de 100, croisez-les et ajoutez-les.
  • += et d'autres opérateurs composés ont été ajoutés en 2008. Utilisez-les pour enregistrer quelques caractères.
  • Les littéraux sont généralement un délimiteur assez bon à des fins de repliement. Vous avez rarement besoin d'un espace ou d'un ;.
  • Utilisez les jointures SQL ANSI si vous en avez besoin. Select*from A,B where conditionest plus court queselect*from A join b on condition
  • Si vous pouvez être assuré que la boucle your fera la première itération, il est préférable de la réécrire en tant que gotoboucle de style do- while.
  • STR()est la fonction la plus courte pour transformer un int en chaîne. Si vous effectuez plusieurs conversions ou devez concaténer de nombreux types de données différents, envisagez la concatfonction. Par exemple, 'hello'+str(@)est plus court que concat('hello',@), mais hello+str(@)+str(@a)est plus long queconcat('hello',@,@a)

Par exemple, ces deux sont sémantiquement équivalents.

while @<100begin/*code*/set @+=1 end
s:/*code*/set @+=1if @<100goto s

Vous pouvez utiliser Valuespour créer une table ou une sous-requête. Ce ne sera vraiment un avantage que si vous avez besoin de quelques lignes constantes.

Michael B
la source
Pour moi, $ est un peu plus évident que \ pour initialiser un nombre à 0 dans un type monétaire. YMMV
user1443098
5

Compression de code à l'aide de SQL

SQL est verbeux, obtient des scores élevés et autant que nous les aimons, SELECT FROM WHEREcoûte 23 octets à chaque utilisation. Vous pouvez compresser ces mots et d'autres mots répétés ou des extraits de code entiers. Cela réduira le coût marginal du code répété à 1 octet! *

Comment cela fonctionne:

  • Une variable est déclarée et affectée au code SQL compressé
  • Un tableau modifie la variable. Chaque ligne dégonfle la variable.
  • La variable modifiée est exécutée.

Le problème:

Le coût initial est proche de 100 octets et chaque ligne de la table de remplacement coûte encore 6 octets. Ce type de logique ne sera pas très efficace à moins que vous ne travailliez avec beaucoup de code que vous ne pouvez pas réduire ou que le défi soit basé sur la compression.

Voici un exemple

Le défi consiste à obtenir les 10 derniers multiples de 2,3 et 5 menant à n. Disons que cela ( 343 octets golfés ) est la meilleure solution que j'ai pu trouver:

WITH x AS(
    SELECT 99 n
UNION ALL 
    SELECT n-1
    FROM x
    WHERE n>1
)
SELECT w.n,t.n,f.n
FROM
    (SELECT n, ROW_NUMBER()OVER(ORDER BY n DESC)r
     FROM x WHERE n%2=0
    )w
,
    (SELECT n, ROW_NUMBER()OVER(ORDER BY n DESC)r
     FROM x WHERE n%3=0
    )t
,   (SELECT n, ROW_NUMBER()OVER(ORDER BY n DESC)r
     FROM x WHERE n%5=0
    )f
WHERE w.r=t.r AND w.r=f.r AND w.r<11
ORDER BY 1

Exemple après compression du code

Cela exécute le même code que ci-dessus, soit environ 302 octets .

DECLARE @a CHAR(999)='
WITH x AS(!99n UNION ALL !n-1 @x#n>1)
!w.n,t.n,f.n@$2=0)w,$3=0)t,$5=0)f
#w.r=t.r AND w.r=f.r AND w.r<11^1'

SELECT @a=REPLACE(@a,LEFT(i,1),SUBSTRING(i,2,99))
FROM(VALUES
  ('$(!n,ROW_NUMBER()OVER(^n DESC)r@x#n%'),
  ('! SELECT '),
  ('@ FROM '),
  ('# WHERE '),
  ('^ ORDER BY ')
)x(i)

EXEC(@a)
comfortablydrei
la source
Excellente stratégie, ce style de remplacement multiple peut également être utile dans des scénarios plus conventionnels.
BradC
1
Après quelques tests, j'ai déterminé que si votre liste de remplacements contient 7 éléments ou moins , vous économiseriez des octets en faisant SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)au lieu d'utiliser une seule colonne avec LEFT()et SUBSTRING(). Si vous en avez 8 ou plus, éviter les guillemets et les virgules supplémentaires est un bon compromis.
BradC
En fait, pour 4 remplacements ou moins, vous économiseriez des octets avec un ancienSET @=REPLACE(REPLACE(REPLACE(...
BradC
4

En voici une drôle. Cela convertira les valeurs d'une colonne en un seul tuple.

EDIT: Merci pour les commentaires. Il semble que le moyen le plus court de remonter sans les balises XML soit:

SELECT (SELECT column1+''
FROM table
ORDER BY column1
FOR XML PATH(''))

Remarque: si XML est une sortie valide, vous pouvez omettre la sélection externe et les parens. De plus column1+'', ne fonctionne que pour les chaînes. Pour les types de numéros, il est préférable de le fairecolumn1+0

comfortablydrei
la source
1
En fait, il reviendra <column_name>value1</column_name><column_name>value2</column_name>.... Afin d'avoir un CSV à partir d'une colonne, vous pouvez DECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(merci pour le premier conseil de @ MichaelB) qui reviendra value1,value2,.... Cependant, il s'agit en fait de 9 caractères de plus que votre astuce XML :(
Jacob
1
Notez que vous pouvez raccourcir ce délai. Ltrimn'est pas nécessaire car select (select ... for xml path ('')) renvoie un nvarchar(max). De plus, pour résoudre le problème des colonnes, utilisez simplement une expression non mutante. Pour les chiffres que vous pouvez faire v+0, pour la chaîne, ajoutez une chaîne vide, etc. Bien que je ne considère pas vraiment cela comme une astuce de golf, c'est malheureusement une réalité de la façon d'écrire des requêtes dans le serveur SQL.
Michael B
3

Il est possible d'utiliser certains opérateurs au niveau du bit dans T-SQL .

Je n'ai pas d'exemple concret, mais je pense que c'est un fait à savoir lorsque l'on joue au golf en T-SQL.

Jacob
la source
1
C'est très valable. Au lieu d'écrire une condition comme x=0 or y=0, vous pouvez l'écrire comme l'équivalent logique x|y=0qui économise pas mal d'octets!
Michael B
3

Imprimer au lieu de sélectionner

C'est aussi simple que ça! Voici donc un polyglotte T-SQL / Python:

print'Hello, World!'

Essayez-le en ligne

mbomb007
la source
3

La notation scientifique est une méthode plus courte pour exprimer des nombres très grands et très petits, par exemple select 1000000000= select 1E9et select 0.000001= select 1E-6.

naXa
la source
2

Michael B a mentionné l'utilisation d'un CTE récursif pour une table numérique , mais n'a pas montré d'exemple. Voici une version MS-SQL que nous avons élaborée dans cet autre thread :

--ungolfed
WITH t AS (
    SELECT 1 n 
    UNION ALL 
    SELECT n + 1
    FROM t 
    WHERE n < 99)
SELECT n FROM t

--golfed
WITH t AS(SELECT 1n UNION ALL SELECT n+1FROM t WHERE n<99)SELECT n FROM t

Notez que vous pouvez modifier la valeur de départ ( 1 n), l' intervalle ( n + 1) et la valeur de fin ( n < 99).

Si vous avez besoin de plus de 100 lignes, vous devrez cependant ajouter option (maxrecursion 0):

WITH t AS(SELECT 0n UNION ALL SELECT n+1FROM t WHERE n<9999)
SELECT n FROM t option(maxrecursion 0)

ou rejoindre le rCTE à lui-même:

WITH t AS(SELECT 0n UNION ALL SELECT n+1FROM t WHERE n<99)
SELECT 100*z.n+t.n FROM t,t z

Bien que ce dernier ne soit pas garanti de retourner dans l'ordre numérique sans ORDER BY 1

BradC
la source
2

Utilisez la compression GZIP pour les chaînes très longues!

Je savais donc que SQL 2016 a ajouté une COMPRESSfonction (et unDECOMPRESS fonction), ce qui (enfin) apporte la possibilité de GZIP une chaîne ou binaire.

Le problème est qu'il n'est pas immédiatement clair comment en profiter pour jouer au golf; COMPRESSpeut prendre une chaîne mais renvoie un VARBINARY, qui est plus court en octets (lorsqu'il est stocké dans un VARBINARYchamp SQL ), mais plus long en caractères (hex brut).

J'ai déjà joué avec ça auparavant, mais j'ai finalement pu mettre en place une version de travail, basée sur cette ancienne réponse sur SO . Ce message n'utilise pas les nouvelles fonctions GZIP, mais il convertit un VARBINARYen une chaîne encodée en Base-64. Nous avions juste besoin d'insérer les nouvelles fonctions au bon endroit et de les jouer un peu.

Voici le code que vous pouvez utiliser pour convertir votre très longue chaîne en chaîne compressée encodée en Base-64:

DECLARE @s VARCHAR(MAX)='Your really long string goes right here'
SELECT CONVERT(VARCHAR(MAX),(SELECT CONVERT(VARBINARY(MAX),COMPRESS(@s))
       FOR XML PATH(''),BINARY BASE64))

Prenez la sortie et utilisez-la dans votre code à la place de la longue chaîne d'origine, avec:

--To use your compressed string and return the original:
DECLARE @e VARCHAR(MAX)='H4sIAAAAAAAEAIvMLy1SKEpNzMmpVMjJz0tXKC4pygRS6fmpxQpFmekZJQoZqUWpAGGwW5YnAAAA'
SELECT CAST(DECOMPRESS(CAST(@e as XML).value('.','varbinary(max)'))AS varchar(max))

Donc, au lieu de votre code d'origine ( 1471 octets )

SELECT'Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate — we can not consecrate — we can not hallow — this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us — that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion — that we here highly resolve that these dead shall not have died in vain — that this nation, under God, shall have a new birth of freedom — and that government of the people, by the people, for the people, shall not perish from the earth.'

vous auriez ceci ( 1034 octets ):

SELECT CAST(DECOMPRESS(CAST('H4sIAAAAAAAEAGVUW47bMAy8Cg/g5hD9aLFA0a8C/aYt2hZWEVNJjpGT5LodinE2i/0JIouPmeFQP3QrVCctQpwDVblKpptwqcSLkt3O3FbBeSy6LWujWUtbSTO1NVaaNLeYJbeBmLLslLlFzYNdTBKvEihm+hVHKe029CZBQpy44aYpighdil60RsvDmRtxSnQGEAasqUiPlX8bpxP91p126TeSF168PtNiYTTFa0y0cxmoSQWwhfZVDL8XPsBpAZLb40hVX9B+QgganCkp6kgOW5ET/fXmZ2mmwdF45NaSfJujpEA6ezfg6PErX8FDz2KEj9pIvUBJ63/E92xoBO3xP3Oi8iBxSTyJKY9ArQJSSiAltFhp8IuFEuBXL/TClc7RhmaXJ3prhJFxarq4KHNsvb6RtikcOkHhuuoGLkH7nE/0fcOIu9SJy4LAKrnKYKGmUdb2Qe3++hXSVpnKl+8rpoxh3t1HC9yVw4n+wA9jMVYwwGC4D3xBGOIY89rKtiwJwzINhkPfow0cAagzY8aj4sZMfFG1n90IKnEIZoEgrfDUvOmuBXT3COulaMM0kCieEdgNUOQsZ9gYEB4K8e0BYNwgbHNm2KBik4LCHgmhbxSigz1mYKPcane/Uxyo9D0bDN8oL0vS5/zYlC3DF7Gu+Ay872gQp9U7mDCzb2jPWN0ZaGJKwOJZx3QD9SvD6uEA4l2feHrvnv9lS93ojeu7ScHAAVFGme3tQOr94eGiZwuHSVeFduKDM70avwscZAtd++er+sqrp068VTf5C63D4HBdRfWtvwxcsYq2Ns8a96dvnTxMD7JYH0093+dQxcFU897DhLgO0V+RK0gdlbopj+cCzoRGPxX+89Se5u/dGPtzOIO5SAD5e3drL7LAfiXDyM13HE+d6CWZY26fjr7ZH+cPgFhJzPspK+FpbuvpP9RXxXK3BQAA'as XML).value('.','varbinary(max)'))AS varchar(max))

Voir cette réponse qui m'a fait économiser près de 200 octets.

Je n'ai pas fait le calcul, mais clairement en raison de la surcharge, cela ne sera efficace que pour les cordes extrêmement longues. Il y a probablement d'autres endroits où cela ne peut pas être utilisé; J'ai déjà découvert que vous devez le faire SELECT, vous ne pouvez pas PRINT, sinon vous obtenez:

Xml data type methods are not allowed in expressions in this context.

EDIT : Version plus courte du code de décompression, gracieuseté de @digscoop :

Économisez 10 octets en changeant l'extérieur CASTen une conversion implicite en utilisant CONCAT:

SELECT CONCAT('',DECOMPRESS(CAST('encoded_string_here'as XML).value('.','varbinary(max)')))

Vous pouvez également déclarer une variable de type XMLau lieu de VARCHAR(MAX)et enregistrer sur l'intérieur CAST:

DECLARE @ XML='encoded_string_here'
SELECT CONCAT('',DECOMPRESS(@.value('.','varbinary(max)')))

C'est un peu plus long en soi, mais si vous en avez besoin dans une variable pour d'autres raisons, cela pourrait aider.

BradC
la source
Bien, je ne connais pas SQL mais ça a l'air cool quand même
MilkyWay90
1

Quelques réflexions sur la création et l'utilisation de tableaux pour les défis:

1. L'entrée SQL peut être prise via une table préexistante

Code méthodes d'entrée / sortie de golf :

Les SQL peuvent prendre des entrées d'une table nommée

La création et le remplissage de ce tableau avec des valeurs d'entrée ne comptent pas dans votre total d'octets, vous pouvez simplement supposer qu'il est déjà là.

Cela signifie que vos calculs peuvent sortir via simple SELECT à partir du tableau d'entrée:

SELECT 2*SQRT(a)FROM t

2. Si possible, ne créez pas du tout de table

Au lieu de (69 octets):

CREATE TABLE t(b INT)
INSERT t VALUES(7),(14),(21),(99)
SELECT b FROM t

Faites juste (43 octets):

SELECT b FROM(VALUES(7),(14),(21),(99))t(b)

3. Si possible, créez la table avec SELECT INTO

Au lieu de (39 octets):

CREATE TABLE t(p INT)
INSERT t VALUES(2)

Faites ceci (17 octets):

SELECT 2 p INTO t

4: Envisagez de mélanger plusieurs colonnes ensemble

Voici deux variantes qui renvoient la même sortie:

SELECT a,b FROM
(VALUES('W','Bob'),('X','Sam'),('Y','Darla'),('Z','Elizabeth'))t(a,b)

SELECT LEFT(a,1),SUBSTRING(a,2,99)FROM
(VALUES('WBob'),('XSam'),('YDarla'),('ZElizabeth'))t(a)

Après quelques tests, la version supérieure (plusieurs colonnes) semble plus courte avec 7 lignes ou moins , la version inférieure (en raison de LEFT et SUBSTRING) est plus courte avec 8 lignes ou plus . Votre kilométrage peut varier en fonction de vos données exactes.

5: Utilisez REPLACE et EXEC pour de très longues séquences de texte

Dans la veine de l'excellente réponse de comfortablydrei , si vous avez 15 valeurs ou plus , utilisez REPLACEun symbole pour vous débarrasser des répétitions'),(' séparateurs entre les éléments:

114 caractères:

SELECT a FROM(VALUES('A'),('B'),('C'),('D'),('E'),('F'),('G'),('H')
,('I'),('J'),('K'),('L'),('M'),('N'),('O'))t(a)

112 caractères:

DECLARE @ CHAR(999)=REPLACE('SELECT a FROM(VALUES(''
 A-B-C-D-E-F-G-H-I-J-K-L-M-N-O''))t(a)','-','''),(''')EXEC(@)

Si vous utilisez déjà du SQL dynamique pour d'autres raisons (ou si vous avez plusieurs remplacements), le seuil où cela vaut la peine est beaucoup plus bas.

6: Utilisez un SELECT avec des colonnes nommées au lieu d'un tas de variables

Inspiré par l'excellente réponse de jmlt ici , réutilisez les chaînes via un SELECT:

SELECT a+b+a+b+d+b+b+a+a+d+a+c+a+c+d+c+c+a+a
FROM(SELECT'Hare 'a,'Krishna 'b,'Rama 'c,'
'd)t

Retour

Hare Krishna Hare Krishna 
Krishna Krishna Hare Hare 
Hare Rama Hare Rama 
Rama Rama Hare Hare 

(Pour MS SQL, j'ai changé le \ten un retour en ligne et changé CONCAT()en +pour économiser des octets).

BradC
la source
1

Balisez votre code pour la coloration syntaxique T-SQL

Au lieu de simplement:

CREATE TABLE t(b INT)
INSERT t VALUES(7),(14),(21),(99)
SELECT b FROM t

Inclure une balise de langue comme celle-ci:

<!-- language: lang-sql -->

    CREATE TABLE t(b INT)
    INSERT t VALUES(7),(14),(21),(99)
    SELECT b FROM t

et le résultat sera:

CREATE TABLE t(b INT)
INSERT t VALUES(7),(14),(21),(99)
SELECT b FROM t
BradC
la source
1

Profitez des nouvelles fonctionnalités / fonctions de MS SQL 2016 et SQL 2017

Si vous n'avez pas de copies locales avec lesquelles travailler, vous pouvez jouer en ligne avec StackExchange Data Explorer (SQL 2016) ou avec dbfiddle.uk (SQL 2016 ou SQL "vNext").

STRING_SPLIT ( SQL 2016 et versions ultérieures )

SELECT *
FROM STRING_SPLIT('one,two,three,four,five',',')

Si vous devez alias la table ou faire référence au nom de la colonne:

SELECT t.value
FROM STRING_SPLIT('one,two,three,four,five',',')t

TRIM ( SQL 2017 ou version ultérieure )

Plus court que RTRIM() et certainement plus court queLTRIM(RTRIM()) .

A également une option pour supprimer d'autres caractères ou ensembles de caractères du début ou de la fin:

SELECT TRIM('sq,0' FROM 'SQL Server 2000')

Retour L Server 2

TRADUIRE ( SQL 2017 ou version ultérieure )

TRANSLATEvous permet de remplacer plusieurs caractères en une seule étape, plutôt qu'un groupe d' REPLACEinstructions imbriquées . Mais ne célébrez pas trop , il ne remplace que des personnages individuels individuels par des personnages uniques différents.

SELECT TRANSLATE('2*[3+4]/{7-2}', '[]{}', '()()');

Chaque caractère de la deuxième chaîne est remplacé par le caractère correspondant de la troisième chaîne.

On dirait que nous pourrions éliminer un tas de personnages avec quelque chose comme REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


Certains plus intéressants aussi, comme CONCAT_WSet STRING_AGGqui valent probablement le coup d'oeil aussi.

BradC
la source
1

Sainte vache, j'ai découvert la merveille de PARSENAME( SQL 2012 ou supérieur ).

La fonction a été conçue pour isoler les parties d'un nom d'objet comme servername.dbname.dbo.tablename, mais elle fonctionne pour toutes les valeurs séparées par des points. N'oubliez pas que cela compte à droite et non à gauche:

SELECT PARSENAME('a.b.c.d',1),      -- d
       PARSENAME('a.b.c.d',2),      -- c
       PARSENAME('a.b.c.d',3),      -- b
       PARSENAME('a.b.c.d',4)       -- a

Si vous avez moins de 4 valeurs séparées par des points, il reviendra NULLpour le reste (mais il compte toujours de droite à gauche ):

SELECT PARSENAME('a.b',1),      -- b
       PARSENAME('a.b',2),      -- a
       PARSENAME('a.b',3),      -- NULL
       PARSENAME('a.b',4)       -- NULL

C'est ici que la magie entre en jeu: combinez-la avec STRING_SPLIT(2016 ou plus) pour créer des tables multi-colonnes en mémoire !!

Vieux et éclaté:

SELECT a,b,c FROM
(VALUES('Bob','W','Smith'),
       ('Sam','X','Johnson'),
       ('Darla','Y','Anderson'),
       ('Elizabeth','Z','Turner'))t(a,b,c)

Nouvelle chaleur:

SELECT PARSENAME(value,3)a,PARSENAME(value,2)b,PARSENAME(value,1)c
FROM string_split('Bob.W.Smith-Sam.X.Johnson-Darla.Y.Anderson-Elizabeth.Z.Turner','-')

De toute évidence, vos économies réelles dépendent de la taille et du contenu de la table et de la façon dont vous l'utilisez.

Notez que si vos champs sont de largeur constante, vous feriez probablement mieux d'utiliser LEFTet RIGHTde les séparer au lieu de PARSENAME(non seulement parce que les noms de fonction sont plus courts, mais aussi parce que vous pouvez éliminer complètement les séparateurs).

BradC
la source
Je ne sais pas quand PARSENAME est sorti, mais il y a des articles le décrivant de 2003
t-clausen.dk
1

Quelques astuces non liées que j'ai vues et que je voulais préserver:

  1. Utilisez GO #pour répéter un bloc un certain nombre de fois .

J'ai vu ce truc intelligent sur l'excellente réponse de Paul .

PRINT'**********'
GO 10

Bien entendu, cela réinitialisera toutes les variables de compteur dans le bloc, vous devrez donc les comparer à une WHILEboucle ou à une x: ... GOTO xboucle.

  1. SELECT TOP ... FROM systypes

À partir de la même question que celle de Paul ci-dessus, Anuj Tripathi a utilisé l'astuce suivante :

SELECT TOP 10 REPLICATE('*',10) FROM systypes

ou, comme suggéré par pinkfloydx33 dans les commentaires:

SELECT TOP 10'**********'FROM systypes

Notez que cela ne repose sur aucun du contenu réel de systypes, juste que la vue système existe (ce qu'elle fait dans chaque base de données MS SQL) et contient au moins 10 lignes (elle semble en contenir 34, pour les versions les plus récentes de SQL ). Je n'ai pas trouvé de vues système avec des noms plus courts (qui ne nécessitaient pas de sys.préfixe), donc cela peut être idéal.

BradC
la source
1

Voir cette question sur dba.stackexchange pour quelques idées intéressantes pour ajouter une colonne numérique à un résultat STRING_SPLIT.

Étant donné une chaîne comme 'one,two,three,four,five', nous voulons obtenir quelque chose comme:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. Selon la réponse de Joe Obbish, utilisez ROW_NUMBER()et triez par NULLou une constante:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. Selon la réponse de Paul White, utilisezSEQUENCE :

    CREATE SEQUENCE s START WITH 1
    SELECT value, NEXT VALUE FOR s 
    FROM STRING_SPLIT('one,two,three,four,five', ',')
    

Les séquences sont des objets persistants intéressants; vous pouvez définir le type de données, la valeur min et max, l'intervalle et si elle se termine au début:

    CREATE SEQUENCE s TINYINT;     --Starts at 0
    CREATE SEQUENCE s MINVALUE 1;  --Shorter than START WITH
    SELECT NEXT VALUE FOR s        --Retrieves the next value from the sequence
    ALTER SEQUENCE s RESTART;      --Restarts a sequence to its original start value
  1. Selon la réponse de Biju jose, vous pouvez utiliser la IDENTITY() fonction (qui n'est pas la même que la IDENTITY propriété en conjonction avec un INSERT:

    SELECT value v,IDENTITY(INT) AS n
    INTO t
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
    SELECT * FROM t
    

Notez que les deux derniers paramètres de IDENTITY(INT,1,1)sont facultatifs et seront définis par défaut sur 1 s'ils sont exclus.

BradC
la source
le problème est que STRING_SPLIT ne garantit aucun ordre de retour. Vous pourriez penser qu'il retournera toujours l'ensemble de lignes dans l'ordre des jetons de la chaîne d'origine. En effet, il peut même faire ça! Cependant, il n'y a aucune garantie dans les documents. c'est bien si vous ne vous souciez pas de la commande. Mais si vous le faites (par exemple, analyser une ligne au format CSV), il y a un problème.
user1443098
1
@ user1443098 Je suis finalement d'accord avec vous dans le contexte de la recommandation de code à des fins commerciales, comme nous pourrions le voir sur dba.SE. Mais pour les défis sur PPCG, mes normes sont un peu différentes; si en testant mon code retourne les lignes dans l'ordre que je veux, alors j'enregistrerai les octets où je pourrai. Similaire à la façon dont je laisserai de côté ORDER BYsi je peux m'en tirer (voir ma réponse à Toasty, Burnt, Brulee , par exemple).
BradC
1

Je viens de découvrir que vous pouvez utiliser des chiffres pour un seul caractère REPLACEpour éliminer les guillemets :

--44 bytes
PRINT REPLACE('Baby Shark******','*',' doo')

--42 bytes
PRINT REPLACE('Baby Shark000000',0,' doo')

C'est parce que REPLACEfait une conversion implicite en chaîne.

Les deux produisent la même sortie:

Baby Shark doo doo doo doo doo doo
BradC
la source
0

_ et # sont des alias valides. Je les utilise avec CROSS APPLY pour faire apparaître les colonnes qu'il renvoie font partie de la clause FROM par exemple

SELECT TOP 10 number, n2
FROM master.dbo.spt_values v
CROSS APPLY (SELECT number*2 n2) _

J'aime ça quand le seul but du CROSS APPLY est de calculer une expression.

D'ailleurs, utiliser APPLY pour calculer des sous-expressions est un bon moyen de rendre votre code DRY-er (et plus court). D'après ce que j'ai vu dans les plans d'exécution, il n'y a aucun coût supplémentaire à cette approche. Le compilateur comprend que vous êtes en train de calculer quelque chose et le traite comme n'importe quelle autre expression.

user1443098
la source
Je trouve que l'application croisée est longue, il est vraiment difficile de trouver une situation utile en utilisant l'application croisée sans trouver une autre méthode plus courte
t-clausen.dk
OK - raccourcissez l'exemple donné ci-dessus!
user1443098
SELECT TOP 10 numéro, numéro * 2 n2 FROM master.dbo.spt_values ​​v
t-clausen.dk
Je veux dire, garder la jointure. Soit dit en passant, une fois que vous avez créé des requêtes xml, CROSS APPLY peut devenir le seul moyen de le faire, car il se peut qu'aucune colonne d'une sous-requête ne fasse une jointure.
user1443098
La sous-sélection est plus courte que l'application croisée: SELECT top 10 * FROM (SELECT numéro n, numéro * 2n2 FROM master..spt_values) x
t-clausen.dk