Tipps zum Golfen in T-SQL

16

Welche allgemeinen Tipps haben Sie zum Golfen in T-SQL? Ich bin auf der Suche nach Ideen, die auf Code-Golf-Probleme im Allgemeinen angewendet werden können, die zumindest etwas spezifisch für T-SQL sind. Bitte posten Sie einen Tipp pro Antwort.

Vielen Dank an Marcog für die originelle Idee. :)

Michael B
quelle
Ein Tipp - verwenden Sie eine andere Sprache zum Golfen. SQL-Antworten erhalten in der Regel nur sehr wenige oder gar keine Gegenstimmen.
t-clausen.dk

Antworten:

16

Meine allgemeine Trickkiste:

  • @ ist eine gültige Variable in t-sql.
  • T-sql 2012 hat iifeine VB-Style-Case-Anweisung hinzugefügt . Dies ist fast immer kürzer als ein Äquivalent if else.
  • \Dies ist eine nützliche Methode, um eine Zahl als 0 in einem Geldtyp zu initialisieren. Sie können einen Wert durch Hinzufügen in einen Gleitkommawert umwandeln e. zB 4eoder \kwas setzt k auf den Wert 0,00 Geld.
  • rCTEscheinen die beste Möglichkeit zu sein, eine Nummerntabelle mit weniger als 100 Einträgen zu erstellen. Noch kürzer als mit spt_values. Wenn Sie mehr als 100 benötigen, fügen Sie diese über Kreuz hinzu.
  • += und andere zusammengesetzte Operatoren wurden 2008 hinzugefügt. Verwenden Sie diese, um einige Zeichen zu sparen.
  • Literale sind normalerweise ein ausreichend gutes Trennzeichen für Aliasing-Zwecke. Sie brauchen selten ein Leerzeichen oder ein ;.
  • Verwenden Sie bei Bedarf ANSI SQL-Joins. Select*from A,B where conditionist kürzer alsselect*from A join b on condition
  • Wenn Sie sicher sein können, dass die while-Schleife die erste Iteration ausführt, schreiben Sie sie am besten als do-while-Stil- gotoSchleife um.
  • STR()ist die kürzeste Funktion, um ein Int in einen String zu verwandeln. Wenn Sie mehr als eine Konvertierung durchführen oder mehrere verschiedene Datentypen zusammenfassen müssen, ziehen Sie die concatFunktion in Betracht . ZB 'hello'+str(@)ist kürzer als concat('hello',@), aber hello+str(@)+str(@a)länger alsconcat('hello',@,@a)

Zum Beispiel sind diese beiden semantisch äquivalent.

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

Mit können Sie Valueseine Tabelle oder Unterabfrage erstellen. Dies ist nur dann von Vorteil, wenn Sie einige konstante Zeilen benötigen.

Michael B
quelle
Für mich ist $ ein bisschen offensichtlicher als \, eine Zahl als 0 in einem Geldtyp zu initialisieren. YMMV
user1443098
5

Codekomprimierung mit SQL

SQL ist wortreich, erzielt hohe Punktzahlen und kostet, so sehr wir es lieben, SELECT FROM WHEREbei jeder Verwendung 23 Byte. Sie können diese und andere wiederholte Wörter oder ganze Codeausschnitte komprimieren. Auf diese Weise verringern sich die Grenzkosten für wiederholten Code auf 1 Byte! *

Wie das funktioniert:

  • Eine Variable wird deklariert und mit komprimiertem SQL-Code versehen
  • Eine Tabelle ändert die Variable. In jeder Zeile wird die Variable entleert.
  • Die geänderte Variable wird ausgeführt.

Das Problem:

Die Vorabkosten liegen bei nahezu 100 Byte, und jede Zeile in der Ersetzungstabelle kostet weitere 6 Byte. Diese Art von Logik ist nur dann sehr effektiv, wenn Sie mit viel Code arbeiten, den Sie nicht kürzen können, oder wenn die Herausforderung auf Komprimierung basiert.

Hier ist ein Beispiel

Die Herausforderung besteht darin, die letzten 10 Vielfachen von 2,3 und 5 zu erhalten, die zu n führen. Nehmen wir an, dies ( 343 Byte Golf ) ist die beste Lösung, die ich finden konnte:

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

Beispiel nachdem der Code komprimiert wurde

Dies führt den gleichen Code wie oben aus, ist mit ~ 302 Bytes belegt .

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)
bequemdrei
quelle
Tolle Strategie, dass Multi-Replace-Stil auch in konventionelleren Szenarien nützlich sein kann.
BradC
1
Nach einigen Tests habe ich festgestellt, dass Sie, wenn Ihre Ersatzliste 7 oder weniger Elemente enthält, Bytes sparen, indem Sie dies tun, SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)anstatt eine einzelne Spalte mit LEFT()und zu verwenden SUBSTRING(). Wenn Sie 8 oder mehr haben, ist es ein guter Kompromiss, die zusätzlichen Anführungszeichen und Kommas zu vermeiden.
BradC
Eigentlich für 4 oder weniger Ersetzungen würden Sie Bytes mit einem altmodischen SET @=REPLACE(REPLACE(REPLACE(...
speichern
4

Hier ist ein lustiger. Dadurch werden die Werte in einer Spalte in ein einzelnes Tupel konvertiert.

EDIT: Danke für die Kommentare. Der kürzeste Weg zum Aufrollen ohne XML-Tags ist:

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

Hinweis: Wenn XML eine gültige Ausgabe ist, können Sie die äußere Auswahl und das Paren weglassen. Auch das column1+''funktioniert nur für Streicher. Für Nummerntypen ist es am besten, dies zu tuncolumn1+0

bequemdrei
quelle
1
Eigentlich wird es zurückkehren <column_name>value1</column_name><column_name>value2</column_name>.... Um eine CSV aus einer Spalte zu erhalten, können Sie DECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(danke für den ersten Tipp von @ MichaelB) diese zurückgeben value1,value2,.... Es ist jedoch tatsächlich 9 Zeichen länger als Ihr XML-Trick :(
Jacob
1
Beachten Sie, dass Sie dies kürzer machen können. Ltrimist nicht notwendig, da select (select ... for xml path ('')) ein zurückgibt nvarchar(max). Verwenden Sie zum Lösen der Spaltensache einfach einen nicht mutierenden Ausdruck. Für Zahlen können Sie tun v+0, für Zeichenfolgen fügen Sie leere Zeichenfolgen usw. hinzu. Obwohl ich dies nicht wirklich als Golftipp betrachte, ist dies leider eine Realität, wie Abfragen in SQL Server geschrieben werden.
Michael B
3

In T-SQL können einige bitweise Operatoren verwendet werden .

Ich habe kein konkretes Beispiel, aber ich glaube, es ist eine gut zu wissende Tatsache, wenn man mit T-SQL Golf spielt.

Jakob
quelle
1
Das ist sehr gültig. Anstatt eine Bedingung wie zu x=0 or y=0schreiben, können Sie diese als logisches Äquivalent schreiben, das x|y=0einige Bytes einspart!
Michael B
3

Wissenschaftliche Notation ist eine kürzere Methode, um sehr große und sehr kleine Zahlen auszudrücken, zB select 1000000000= select 1E9und select 0.000001= select 1E-6.

naXa
quelle
2

Michael B erwähnte die Verwendung eines rekursiven CTE für eine Nummerntabelle , zeigte jedoch kein Beispiel. Hier ist eine MS-SQL-Version, die wir in diesem anderen Thread ausgearbeitet haben :

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

Beachten Sie, dass Sie den Startwert ( 1 n), das Intervall ( n + 1) und den Endwert ( n < 99) ändern können .

Wenn Sie jedoch mehr als 100 Zeilen benötigen, müssen Sie Folgendes hinzufügen option (maxrecursion 0):

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

oder treten Sie dem rCTE bei:

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

Obwohl nicht garantiert ist, dass der letzte Befehl in numerischer Reihenfolge ohne ein zurückgegeben wird ORDER BY 1

BradC
quelle
2

Verwenden Sie die GZIP-Komprimierung für sehr lange Zeichenfolgen!

Daher wusste ich, dass SQL 2016 eine COMPRESSFunktion (und eine DECOMPRESSFunktion) hinzugefügt hat , die (endlich) die Möglichkeit bietet, einen String oder eine Binärdatei mit GZIP zu versehen.

Das Problem ist, dass es nicht sofort klar ist, wie man dies zum Golfen nutzen kann. COMPRESSkann eine Zeichenfolge annehmen, gibt jedoch a zurück VARBINARY, das in Bytes kürzer ist (wenn es in einem SQL- VARBINARYFeld gespeichert ist), in Zeichen jedoch länger ist (unformatiertes Hex).

Ich habe damit schon früher gespielt, konnte aber endlich eine funktionierende Version zusammenstellen, basierend auf dieser alten Antwort auf SO . Dieser Beitrag verwendet die neuen GZIP-Funktionen nicht, konvertiert jedoch eine VARBINARYin eine Base-64-codierte Zeichenfolge. Wir mussten nur die neuen Funktionen an der richtigen Stelle einfügen und ein bisschen Golf spielen.

Hier ist der Code, mit dem Sie Ihre sehr lange Zeichenfolge in die Base-64-codierte komprimierte Zeichenfolge konvertieren können:

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

Nehmen Sie die Ausgabe und verwenden Sie sie in Ihrem Code anstelle der ursprünglichen langen Zeichenfolge, zusammen mit:

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

Also anstelle Ihres ursprünglichen Codes ( 1471 Bytes )

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

Sie würden dies haben ( 1034 Bytes ):

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

Siehe diese Antwort, die mir fast 200 Bytes erspart hat.

Ich habe nicht nachgerechnet, aber aufgrund des Overheads wird dies nur für extrem lange Saiten effektiv sein. Es gibt wahrscheinlich andere Orte, an denen dies nicht möglich ist. Ich habe bereits herausgefunden, dass du SELECTes musst, du kannst es nicht PRINT, sonst bekommst du:

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

EDIT : Kürzere Version des Dekomprimierungscodes mit freundlicher Genehmigung von @digscoop :

Sparen Sie 10 Bytes, indem Sie die äußere CASTin eine implizite Konvertierung ändern CONCAT:

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

Sie können XMLanstelle von auch eine Variable vom Typ deklarieren VARCHAR(MAX)und im Inneren speichern CAST:

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

Dies ist an sich etwas länger, aber wenn Sie es aus anderen Gründen in einer Variablen benötigen, kann es hilfreich sein.

BradC
quelle
Schön, ich kenne SQL nicht, aber das sieht immer noch cool aus
MilkyWay90
1

Ein paar Gedanken zum Erstellen und Verwenden von Tabellen für Herausforderungen:

1. Die SQL-Eingabe kann über eine bereits vorhandene Tabelle erfolgen

Code Golf Eingabe / Ausgabemethoden :

SQLs können Eingaben von einer benannten Tabelle erhalten

Das Erstellen und Auffüllen dieser Tabelle mit Eingabewerten zählt nicht für Ihre Bytesumme. Sie können lediglich davon ausgehen, dass sie bereits vorhanden ist.

Dies bedeutet, dass Ihre Berechnungen über einfaches SELECT aus der Eingabetabelle ausgegeben werden können:

SELECT 2*SQRT(a)FROM t

2. Erstellen Sie nach Möglichkeit überhaupt keine Tabelle

Anstelle von (69 Bytes):

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

Mach einfach (43 Bytes):

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

3. Erstellen Sie nach Möglichkeit die Tabelle mit einem SELECT INTO

Anstelle von (39 Bytes):

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

Tun Sie dies (17 Bytes):

SELECT 2 p INTO t

4: Überlegen Sie, ob Sie mehrere Spalten zusammenfügen möchten

Hier sind zwei Varianten, die dieselbe Ausgabe zurückgeben:

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)

Nach einigen Tests ist die obere Version (mehrere Spalten) mit 7 oder weniger Zeilen kürzer , die untere Version (aufgrund von LEFT und SUBSTRING) mit 8 oder mehr Zeilen kürzer . Ihr Kilometerstand kann je nach Ihren genauen Daten variieren.

5: Verwenden Sie REPLACE und EXEC für sehr lange Textsequenzen

In der Ader der ausgezeichneten Antwort des comfortablydrei , wenn Sie 15 oder mehr Werte , die Verwendung REPLACEauf einem Symbol loszuwerden, die wiederholt zu bekommen '),('Separatoren zwischen den Elementen:

114 Zeichen:

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

112 Zeichen:

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

Wenn Sie aus anderen Gründen bereits dynamisches SQL verwenden (oder mehrere Ersetzungen haben), ist der Schwellenwert, bei dem dies sinnvoll ist, viel niedriger.

6: Verwenden Sie ein SELECT mit benannten Spalten anstelle einer Reihe von Variablen

Inspiriert von der hervorragenden Antwort von jmlt hier , verwenden Sie Strings über ein SELECT erneut:

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

kehrt zurück

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

(Für MS SQL habe ich das \tin ein Inline-Return geändert CONCAT()und +in um Bytes zu sparen).

BradC
quelle
1

Kennzeichnen Sie Ihren Code für die Hervorhebung der T-SQL-Syntax

Anstatt nur:

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

Fügen Sie ein Sprach-Tag wie das folgende hinzu:

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

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

und das Ergebnis wird sein:

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

Nutzen Sie die neuen Funktionen in MS SQL 2016 und SQL 2017

Wenn Sie keine lokalen Kopien zum Arbeiten haben, können Sie mit dem StackExchange Data Explorer (SQL 2016) oder mit dbfiddle.uk (SQL 2016 oder SQL "vNext") online spielen .

STRING_SPLIT ( SQL 2016 und höher )

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

Wenn Sie die Tabelle aliasen oder auf den Spaltennamen verweisen müssen:

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

TRIM ( SQL 2017 oder höher )

Kürzer als RTRIM()und sicherlich kürzer als LTRIM(RTRIM()).

Es besteht auch die Möglichkeit, andere Zeichen oder Zeichensätze entweder vom Anfang oder vom Ende zu entfernen :

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

kehrt zurück L Server 2

TRANSLATE ( SQL 2017 oder höher )

TRANSLATEErmöglicht das Ersetzen mehrerer Zeichen in einem Schritt anstelle mehrerer verschachtelter REPLACEAnweisungen. Feiern Sie aber nicht zu viel, es werden nur einzelne Zeichen durch unterschiedliche Einzelzeichen ersetzt.

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

Jedes Zeichen in der zweiten Zeichenfolge wird durch das entsprechende Zeichen in der dritten Zeichenfolge ersetzt.

Sieht so aus, als könnten wir eine Menge Charaktere mit so etwas wie eliminieren REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


Einige weitere interessante, wie CONCAT_WSund STRING_AGGdie sind wahrscheinlich auch einen Blick wert.

BradC
quelle
1

Heilige Kuh, ich habe das Wunder von PARSENAME( SQL 2012 oder höher ) entdeckt.

Die Funktion wurde erstellt, um die Teile eines Objektnamens zu isolieren servername.dbname.dbo.tablename, funktioniert jedoch für alle durch Punkte getrennten Werte. Denken Sie daran, es zählt von rechts , nicht von links:

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

Wenn Sie weniger als 4 durch Punkte getrennte Werte haben, wird dieser NULLfür den Rest zurückgegeben (zählt jedoch weiterhin von rechts nach links ):

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

Hier kommt die Magie ins Spiel: Kombinieren Sie sie mit STRING_SPLIT(2016 oder höher), um In-Memory-Mehrspaltentabellen zu erstellen !!

Alt und kaputt:

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

Neue Schärfe:

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

Ihre tatsächlichen Einsparungen hängen natürlich von der Größe und dem Inhalt der Tabelle ab und davon, wie genau Sie sie verwenden.

Beachten Sie, dass Sie bei Feldern mit konstanter Breite wahrscheinlich besser die Option LEFTund verwenden RIGHT, um sie zu trennen PARSENAME(nicht nur, weil die Funktionsnamen kürzer sind, sondern auch, weil Sie die Trennzeichen vollständig entfernen können).

BradC
quelle
Ich bin nicht sicher, wann PARSENAME herauskam, aber es gibt Artikel, die es von 2003 beschreiben
t-clausen.dk
1

Noch ein paar verwandte Tricks, die ich gesehen und bewahren wollte:

  1. Verwenden Sie GO #diese Taste, um einen Block eine bestimmte Anzahl von Malen zu wiederholen .

Ich habe diesen cleveren Trick bei Pauls exzellenter Antwort gesehen .

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

Dies würde natürlich alle Zählervariablen im Block zurücksetzen, so dass Sie dies gegen eine WHILESchleife oder eine x: ... GOTO xSchleife abwägen müssten .

  1. SELECT TOP ... FROM systypes

Aus der gleichen Frage wie Paulus oben verwendete Anuj Tripathi den folgenden Trick :

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

oder, wie von pinkfloydx33 in den Kommentaren vorgeschlagen:

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

Hinweis : Dies beruht nicht auf einen der tatsächlichen Inhalte von systypes, nur , dass die Systemansicht existiert (was es tut in jeder MS SQL - Datenbank) und enthält mindestens 10 Zeilen (es sieht aus 34 enthält, für die neuesten Versionen von SQL ). Ich konnte keine Systemansichten mit kürzeren Namen finden (für die kein sys.Präfix erforderlich war ), daher ist dies möglicherweise ideal.

BradC
quelle
1

In dieser Frage auf dba.stackexchange finden Sie einige interessante Ideen zum Hinzufügen einer Zahlenspalte zu einem STRING_SPLIT-Ergebnis.

Bei einer Zeichenfolge wie 'one,two,three,four,five'möchten wir Folgendes erhalten:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. Per Joe Obbishs Antwort, Verwendung ROW_NUMBER()und Reihenfolge nach NULLoder einer Konstanten:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. Verwenden Sie fürSEQUENCE die Antwort von Paul White Folgendes :

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

Sequenzen sind interessante persistente Objekte; Sie können den Datentyp, den Min- und Max-Wert, das Intervall und den Zeilenumbruch definieren:

    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 Biju Joses Antwort können Sie die IDENTITY() Funktion (die nicht mit der IDENTITY Eigenschaft in Verbindung mit einem INSERT identisch ist) verwenden :

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

Beachten Sie, dass die letzten beiden Parameter in IDENTITY(INT,1,1)optional sind und standardmäßig 1 sind, wenn sie ausgeschlossen werden.

BradC
quelle
Das Problem ist, dass STRING_SPLIT keine Rückgabe garantiert. Sie können sich vorstellen, dass das Rowset immer in der Reihenfolge der Token in der ursprünglichen Zeichenfolge zurückgegeben wird. Tatsächlich kann es das sogar tun! Es gibt jedoch keine Garantie in den Dokumenten. Das ist in Ordnung, wenn Sie sich nicht für die Bestellung interessieren. Wenn Sie dies jedoch tun (z. B. das Parsen einer Zeile im CSV-Format), liegt ein Problem vor.
user1443098
1
@ user1443098 Letztendlich stimme ich Ihnen im Zusammenhang mit der Empfehlung von Code für geschäftliche Zwecke zu, wie wir es vielleicht auf dba.SE sehen. Bei PPCG-Herausforderungen sind meine Standards jedoch etwas anders. Wenn mein Code beim Testen Zeilen in der von mir gewünschten Reihenfolge zurückgibt, speichere ich die Bytes, wo ich kann. Ähnlich wie ich weglassen werde, ORDER BYwenn ich damit durchkomme (siehe meine Antwort auf Toasty, Burnt, Brulee zum Beispiel).
BradC
1

Soeben wurde festgestellt, dass Sie Ziffern für ein einzelnes Zeichen verwenden können REPLACE, um Anführungszeichen zu entfernen :

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

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

Dies liegt daran, REPLACEdass eine implizite Konvertierung in einen String erfolgt.

Beide erzeugen die gleiche Ausgabe:

Baby Shark doo doo doo doo doo doo
BradC
quelle
0

_ und # sind gültige Aliase. Ich benutze sie mit CROSS APPLY, um es so erscheinen zu lassen, dass die Spalten, die es zurückgibt, Teil der FROM-Klausel sind, z

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

Das gefällt mir, wenn der einzige Zweck von CROSS APPLY darin besteht, einen Ausdruck zu berechnen.

Übrigens ist die Verwendung von APPLY zur Berechnung von Unterausdrücken eine gute Möglichkeit, Ihren Code trockener (und kürzer) zu machen. Nach dem, was ich in den Ausführungsplänen gesehen habe, entstehen diesem Ansatz keine zusätzlichen Kosten. Der Compiler stellt fest, dass Sie nur etwas berechnen, und behandelt es wie jeden anderen Ausdruck.

user1443098
quelle
Ich finde Cross Apply zu lang, es ist wirklich schwer, eine nützliche Situation mit Cross
Apply
OK - verkürzen Sie das obige Beispiel!
user1443098
SELECT TOP 10 Nummer, Nummer * 2 n2 FROM master.dbo.spt_values ​​v
t-clausen.dk
Ich meine, die Verbindung zu behalten. Übrigens: Sobald Sie XML-Abfragen erstellt haben, kann CROSS APPLY die einzige Möglichkeit sein, dies zu tun, da möglicherweise keine Spalten in einer Unterabfrage vorhanden sind, für die ein Join ausgeführt werden soll.
user1443098
Subselect ist kürzer als cross apply: SELECT top 10 * FROM (SELECT number n, number * 2n2 FROM master..spt_values) x
t-clausen.dk