Suggerimenti per giocare a golf in T-SQL


16

Quali consigli generali hai per giocare a golf in T-SQL? Sto cercando idee che possano essere applicate ai problemi del codice golf in generale, almeno in qualche modo specifiche per T-SQL. Si prega di inviare un suggerimento per risposta.

Grazie a Marcog per l'idea originale. :)


un consiglio: usa una lingua diversa per giocare a golf. Le risposte Sql di solito ricevono pochissimi o nessun voto.
t-clausen.dk

Risposte:


16

La mia borsa di trucchi generale ::

  • @ è una variabile valida in t-sql.
  • T-sql 2012 ha aggiunto iifun'istruzione case in stile VB. Questo è quasi sempre più breve di un equivalenteif else .
  • \è un modo utile per inizializzare un numero come 0 in un tipo di denaro. È possibile convertire un valore in float aggiungendo e. ad esempio 4eo \kche imposterà k sul valore di 0,00 soldi.
  • rCTEsembra essere il modo migliore per creare una tabella numerica inferiore a 100 voci. Ancora più breve rispetto all'utilizzo di spt_values. Se hai bisogno di più di un 100, incrocia i join e aggiungili.
  • += e altri operatori composti sono stati aggiunti nel 2008. Usali per salvare alcuni caratteri.
  • I letterali sono di solito un delimitatore abbastanza buono per scopi di aliasing. Raramente hai bisogno di uno spazio o di un; .
  • Usa i join ANSI SQL se ne hai bisogno. Select*from A,B where conditionè più corto diselect*from A join b on condition
  • Se puoi essere certo che il tuo ciclo while farà la prima iterazione, è meglio riscriverlo come stile do-while goto ciclo .
  • STR()è la funzione più breve per trasformare un int in una stringa. Se stai eseguendo più di una conversione o potresti dover concedere numerosi tipi di dati diversi, considera la concatfunzione. Ad esempio 'hello'+str(@)è più corto di concat('hello',@), ma hello+str(@)+str(@a)è più lungo diconcat('hello',@,@a)

Ad esempio Questi due sono semanticamente equivalenti.

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

È possibile utilizzare Valuesper creare una tabella o una sottoquery. Questo sarà davvero un vantaggio se hai bisogno di poche righe costanti.


Per me, $ è un po 'più ovvio di \ per inizializzare un numero come 0 in un tipo di denaro. YMMV
user1443098

5

Compressione del codice tramite SQL

SQL è prolisso, ha un punteggio elevato e per quanto li amiamo, SELECT FROM WHERE costa 23 byte con ogni utilizzo. Puoi comprimere queste e altre parole ripetute o interi frammenti di codice. In questo modo il costo marginale del codice ripetuto si riduce a 1 byte! *

Come funziona:

  • Una variabile viene dichiarata e assegnata al codice SQL compresso
  • Una tabella modifica la variabile. Ogni riga sgonfia la variabile.
  • La variabile modificata viene eseguita.

Il problema:

Il costo iniziale è vicino a 100 byte e ogni riga nella tabella di sostituzione costa altri 6 byte. Questo tipo di logica non sarà molto efficace a meno che tu non stia lavorando con un sacco di codice che non puoi tagliare o la sfida è basata sulla compressione.

Ecco un esempio

La sfida è ottenere gli ultimi 10 multipli di 2,3 e 5 che portano a n. Diciamo che questo ( 343 byte di golf ) è la soluzione migliore che ho potuto trovare:

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

Esempio dopo la compressione del codice

Questo esegue lo stesso codice di cui sopra, con golf di ~ 302 byte .

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)

Ottima strategia, quello stile multi-sostituzione può essere utile anche in scenari più convenzionali.
BradC,

1
Dopo alcuni test, ho stabilito che se il tuo elenco di sostituzioni ha 7 o meno elementi, risparmierai byte facendo SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)invece di usare una singola colonna con LEFT()e SUBSTRING(). Se ne hai 8 o più, evitare le virgolette e le virgole extra è un buon compromesso.
BradC,

In realtà per 4 o meno sostituzioni, risparmieresti byte con un vecchio stileSET @=REPLACE(REPLACE(REPLACE(...
BradC

4

Eccone uno divertente. Questo convertirà i valori in una colonna in una singola tupla.

EDIT: Grazie per i commenti. Sembra che il modo più breve di eseguire il rollup senza i tag XML sia:

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

Nota: se XML è un output valido è possibile omettere la selezione esterna e le parentesi. Inoltre column1+'', funziona solo per le stringhe. Per i tipi di numero è meglio farecolumn1+0


1
In realtà tornerà <column_name>value1</column_name><column_name>value2</column_name>.... Per avere un CSV da una colonna puoi DECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(grazie per il primo consiglio di @ MichaelB) che tornerà value1,value2,.... Tuttavia, in realtà è più lungo di 9 caratteri del tuo trucco XML :(
Jacob

1
Nota che puoi accorciarlo. Ltrimnon è necessario poiché select (seleziona ... per percorso xml ('')) restituisce un nvarchar(max). Inoltre, per risolvere la questione colonna basta usare un'espressione non mutante. Per i numeri che puoi fare v+0, per le stringhe aggiungi stringhe vuote ecc. Anche se non lo considero davvero un suggerimento per il golf, questa è purtroppo una realtà di come scrivere query in SQL Server.
Michael B,

3

È possibile utilizzare alcuni operatori bit a bit in T-SQL .

Non ho un esempio concreto, ma credo che sia un fatto ben noto quando si gioca a golf in T-SQL.


1
Questo è molto valido Invece di scrivere una condizione simile x=0 or y=0, puoi scriverla come l'equivalente logicamente x|y=0che consente di risparmiare parecchi byte!
Michael B,

3

Stampa invece di Seleziona

E 'così semplice! Quindi ecco un poliglotta T-SQL / Python:

print'Hello, World!'

Provalo online


3

La notazione scientifica è un metodo più breve per esprimere numeri molto grandi e molto piccoli, ad esempio select 1000000000= select 1E9e select 0.000001= select 1E-6.


2

Michael B ha menzionato l'uso di un CTE ricorsivo per una tabella numerica , ma non ha mostrato un esempio. Ecco una versione MS-SQL che abbiamo elaborato in questo altro 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

Tieni presente che puoi modificare il valore iniziale ( 1 n), l' intervallo ( n + 1) e il valore finale (n < 99 ).

Se hai bisogno di più di 100 righe, dovrai aggiungere option (maxrecursion 0):

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

o unisciti a rCTE a se stesso:

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

Anche se quest'ultimo non è garantito per tornare in ordine numerico senza un ORDER BY 1


2

Usa la compressione GZIP per stringhe molto lunghe!

Quindi sapevo che SQL 2016 ha aggiunto una COMPRESSfunzione (e una DECOMPRESSfunzione), che (finalmente) porta la possibilità di GZIP una stringa o binario.

Il problema è che non è immediatamente chiaro come trarne vantaggio per il golf; COMPRESSpuò prendere una stringa ma restituisce a VARBINARY, che è più breve in byte (se memorizzato in un VARBINARYcampo SQL ), ma è più lungo in caratteri (esadecimale non elaborato).

Ci ho già giocato prima, ma alla fine sono riuscito a mettere insieme una versione funzionante, basata su questa vecchia risposta su SO . Quel post non utilizza le nuove funzioni GZIP, ma converte aVARBINARY stringa codificata in Base 64. Dovevamo solo inserire le nuove funzioni nel posto giusto e giocarci un po '.

Ecco il codice che puoi usare per convertire la tua stringa molto lunga nella stringa compressa codificata 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))

Prendi l'output e usalo nel tuo codice al posto della stringa lunga originale, insieme a:

--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))

Quindi, invece del tuo codice originale ( 1471 byte )

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.'

avresti questo ( 1034 byte ):

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))

Vedi questa risposta che mi ha salvato quasi 200 byte.

Non ho fatto la matematica, ma chiaramente a causa dell'overhead questo sarà efficace solo per stringhe estremamente lunghe. Probabilmente ci sono altri posti in cui questo non può essere usato; Ho già scoperto che devi SELECTfarlo, non puoi PRINT, altrimenti ottieni:

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

EDIT : versione più breve del codice decompressivo, per gentile concessione di @digscoop :

Salva 10 byte modificando l'esterno CASTin una conversione implicita usando CONCAT:

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

Puoi anche dichiarare una variabile di tipo XMLanziché VARCHAR(MAX)e salvare sul lato interno CAST:

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

Questo è leggermente più lungo da solo, ma se ne hai bisogno in una variabile per altri motivi, potrebbe essere d'aiuto.


Bello, non conosco SQL ma sembra ancora bello
MilkyWay90

1

Alcuni pensieri sulla creazione e l'utilizzo di tabelle per le sfide:

1. L'input SQL può essere acquisito tramite una tabella preesistente

Metodi di input / output di Code Golf :

Gli SQL possono ricevere input da una tabella denominata

La creazione e il popolamento di questa tabella con i valori di input non contano ai fini del totale dei byte, si può semplicemente supporre che sia già presente.

Ciò significa che i tuoi calcoli possono essere emessi tramite il semplice SELECT dalla tabella di input:

SELECT 2*SQRT(a)FROM t

2. Se possibile, non creare affatto una tabella

Invece di (69 byte):

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

Basta fare (43 byte):

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

3. Se possibile, creare la tabella con un SELECT INTO

Invece di (39 byte):

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

Fai questo (17 byte):

SELECT 2 p INTO t

4: considera la possibilità di unire più colonne insieme

Ecco due varianti che restituiscono lo stesso output:

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)

Dopo alcuni test, la versione superiore (più colonne) sembra più corta con 7 o meno righe , la versione inferiore (a causa di SINISTRA e SUBSTRING) è più corta con 8 o più righe . Il chilometraggio può variare, a seconda dei dati esatti.

5: utilizzare REPLACE ed EXEC per sequenze di testo molto lunghe

Sulla scia dell'ottima risposta di drei comodamente , se hai 15 o più valori , usa REPLACEun simbolo per eliminare i ripetuti '),('separatori tra gli elementi:

114 caratteri:

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

112 caratteri:

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(@)

Se lo sei già utilizzando SQL dinamico per altri motivi (o hai più sostituzioni), la soglia in cui vale la pena è molto più bassa.

6: utilizzare un SELEZIONA con colonne denominate anziché un gruppo di variabili

Ispirato dall'ottima risposta di jmlt qui , riutilizzare le stringhe tramite 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

ritorna

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

(Per MS SQL ho modificato il \tin un ritorno in linea e modificato CONCAT()in +per salvare byte).


1

Contrassegna il codice per l'evidenziazione della sintassi T-SQL

Invece di solo:

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

Includi un tag di lingua come questo:

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

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

e il risultato sarà:

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

1

Approfitta delle nuove caratteristiche / funzioni in MS SQL 2016 e SQL 2017

Se non disponi di copie locali con cui lavorare, puoi giocare online con StackExchange Data Explorer (SQL 2016) o con dbfiddle.uk (SQL 2016 o SQL "vNext").

STRING_SPLIT ( SQL 2016 e versioni successive )

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

Se è necessario alias la tabella o fare riferimento al nome della colonna:

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

TRIM ( SQL 2017 o successivo )

Più corto di RTRIM()e sicuramente più corto di LTRIM(RTRIM()).

Ha anche un'opzione per rimuovere altri caratteri o insiemi di caratteri dall'inizio o dalla fine:

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

ritorna L Server 2

TRADUZIONE ( SQL 2017 o successivo )

TRANSLATEconsente di sostituire più caratteri in un solo passaggio, anziché un gruppo di REPLACEistruzioni nidificate . Ma non festeggiare troppo , sostituisce solo singoli personaggi singoli con diversi personaggi singoli.

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

Ogni carattere nella seconda stringa viene sostituito dal carattere corrispondente nella terza stringa.

Sembra che potremmo eliminare un sacco di personaggi con qualcosa del genere REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


Alcuni anche più interessanti, come CONCAT_WSe STRING_AGGche probabilmente meritano una visita.


1

Vacca sacra, ho scoperto la meraviglia di PARSENAME( SQL 2012 o superiore ).

La funzione è stata creata per isolare le parti del nome di un oggetto come servername.dbname.dbo.tablename, ma funziona per qualsiasi valore separato da punti. Ricorda solo che conta da destra , non da sinistra:

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

Se hai meno di 4 valori separati da punti, tornerà NULLper il resto (ma conta comunque da destra a sinistra ):

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

Ecco dove entra in gioco la magia: combinala con STRING_SPLIT(2016 o superiore) per creare tabelle multi-colonna in memoria !!

Vecchio e rotto:

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

Nuova piccantezza:

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','-')

Chiaramente i tuoi risparmi effettivi dipendono dalle dimensioni e dal contenuto della tabella e da come lo stai usando esattamente.

Nota che se i tuoi campi sono a larghezza costante, probabilmente stai meglio usando LEFTe RIGHTper separarli invece di PARSENAME(non solo perché i nomi delle funzioni sono più brevi, ma anche perché puoi eliminare completamente i separatori).


Non sono sicuro quando uscì PARSENAME, ma ci sono articoli che lo descrivono dal 2003
t-clausen.dk

1

Un altro paio di trucchi non correlati che ho visto e che volevo preservare:

  1. Utilizzare GO #per ripetere un blocco un numero specifico di volte .

Ho visto questo trucco intelligente sulla risposta eccellente di Paul .

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

Questo, ovviamente, resetterebbe qualsiasi variabile del contatore nel blocco, quindi dovresti pesare questo contro a WHILE loop o un x: ... GOTO xloop.

  1. SELECT TOP ... FROM systypes

Dalla stessa domanda di Paul sopra, Anuj Tripathi ha usato il seguente trucco :

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

o, come suggerito da pinkfloydx33 nei commenti:

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

Nota che questo non si basa su nessuno dei contenuti effettivi di systypes, solo che esiste la vista di sistema (che fa in ogni database MS SQL) e contiene almeno 10 righe (sembra contenere 34, per le versioni più recenti di SQL ). Non sono riuscito a trovare viste di sistema con nomi più brevi (che non richiedevano un sys.prefisso), quindi potrebbe essere l'ideale.


1

Vedere questa domanda su dba.stackexchange per alcune idee interessanti per l'aggiunta di una colonna numerica a un risultato STRING_SPLIT.

Data una stringa come 'one,two,three,four,five', vogliamo ottenere qualcosa del tipo:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. Per la risposta di Joe Obbish, utilizzare ROW_NUMBER()e ordinare per NULLo una costante:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. Per la risposta di Paul White, usa unSEQUENCE :

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

Le sequenze sono interessanti oggetti persistenti; puoi definire il tipo di dati, il valore minimo e massimo, l'intervallo e se si avvolge all'inizio:

    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. Per la risposta di Biju jose, è possibile utilizzare la IDENTITY() funzione (che non è la stessa della IDENTITY proprietà in combinazione con un INSERT:

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

Si noti che gli ultimi due parametri in IDENTITY(INT,1,1)sono facoltativi e per impostazione predefinita saranno 1 se esclusi.


il problema è che STRING_SPLIT non garantisce alcun ordine di reso. Potresti pensare che restituirà sempre il set di righe nell'ordine dei token nella stringa originale. Anzi, potrebbe persino farlo! Tuttavia, non c'è garanzia nei documenti. va bene se non ti interessa l'ordine. Ma se lo fai (ad esempio analizzando una riga in formato CSV), c'è un problema.
user1443098

1
@ user1443098 Alla fine sono d'accordo con te nel contesto della raccomandazione del codice per scopi commerciali, come potremmo vedere su dba.SE. Ma per le sfide su PPCG i miei standard sono leggermente diversi; se durante il test il mio codice restituisce le righe nell'ordine desiderato, salverò i byte dove posso. Simile a come tralascerò ORDER BYse riesco a cavarmela (vedi la mia risposta a Toasty, Burnt, Brulee , per esempio).
BradC,

1

Ho appena scoperto che puoi usare i numeri per un singolo carattere REPLACEper eliminare le virgolette :

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

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

Questo perché REPLACEesegue una conversione implicita in stringa.

Entrambi producono lo stesso output:

Baby Shark doo doo doo doo doo doo

0

_ e # sono alias validi. Li uso con CROSS APPLY per far apparire le colonne che restituisce fanno parte della clausola FROM ad es

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

Mi piace quando l'unico scopo di CROSS APPLY è calcolare un'espressione.

In ogni caso, l'utilizzo di APPLY per il calcolo di sottoespressioni è un modo semplice per rendere il tuo codice DRY-er (e più breve). Da quanto ho visto nei piani di esecuzione, questo approccio non comporta costi aggiuntivi. Il compilatore capisce che stai solo calcolando qualcosa e lo tratta come qualsiasi altra espressione.


Trovo cross applicare a lungo, è davvero difficile trovare una situazione utile usando cross apply senza trovare un altro metodo più breve
t-clausen.dk

OK - accorcia l'esempio dato sopra!
user1443098

SELEZIONA TOP 10 numero, numero * 2 n2 DA master.dbo.spt_values ​​v
t-clausen.dk

Voglio dire, mantenendo l'unione. A proposito, una volta create query xml, CROSS APPLY può diventare l'unico modo per farlo, dal momento che potrebbe non esserci alcuna colonna in una sottoquery a cui fare un join.
user1443098

La sottoselezione è più corta della croce applicata: SELEZIONA top 10 * DA (SELEZIONA numero n, numero * 2n2 DA master..spt_values) x
t-clausen.dk
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.