Wskazówki do gry w golfa w T-SQL

16

Jakie masz ogólne wskazówki na temat gry w golfa w T-SQL? Szukam pomysłów, które można zastosować do ogólnych problemów z golfem, które są przynajmniej nieco specyficzne dla T-SQL. Proszę zamieścić jedną wskazówkę na odpowiedź.

Dzięki Marcog za oryginalny pomysł. :)

Michael B.
źródło
wskazówka - użyj innego języka do gry w golfa. Odpowiedzi na sql zwykle otrzymują bardzo mało lub wcale nie są pozytywne.
t-clausen.dk

Odpowiedzi:

16

Moja ogólna torba sztuczek:

  • @ jest poprawną zmienną w t-sql.
  • T-sql 2012 dodał iifinstrukcję przypadku w stylu VB. Jest to prawie zawsze krótsze niż odpowiednik if else.
  • \to przydatny sposób na zainicjowanie liczby jako 0 w typie pieniężnym. Możesz przekonwertować wartość na zmiennoprzecinkową, dodając e. np. 4elub \kktóra ustawi k na wartość 0,00 pieniędzy.
  • rCTEwydaje się być najlepszym sposobem na utworzenie tabeli liczb zawierającej mniej niż 100 wpisów. Nawet krótszy niż przy użyciu spt_values. Jeśli potrzebujesz więcej niż 100, połącz krzyżowo i dodaj je.
  • += i inne operatory złożone zostały dodane w 2008 roku. Użyj ich, aby zaoszczędzić kilka znaków.
  • Literały są zwykle wystarczająco dobrym ogranicznikiem do celów aliasingu. Rzadko potrzebujesz miejsca lub ;.
  • Użyj sprzężeń ANSI SQL, jeśli ich potrzebujesz. Select*from A,B where conditionjest krótszy niżselect*from A join b on condition
  • Jeśli możesz mieć pewność, że twoja pętla while wykona pierwszą iterację, najlepiej przepisać ją jako gotopętlę stylu do- while.
  • STR()to najkrótsza funkcja służąca do zamiany int na ciąg. Jeśli wykonujesz więcej niż jedną konwersję lub konieczne może być połączenie wielu różnych typów danych, rozważ tę concatfunkcję. Np. 'hello'+str(@)Jest krótszy niż concat('hello',@), ale hello+str(@)+str(@a)dłuższy niżconcat('hello',@,@a)

Na przykład te dwa są semantycznie równoważne.

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

Możesz użyć Valuesdo utworzenia tabeli lub podzapytania. Będzie to naprawdę korzystne, jeśli potrzebujesz kilku stałych rzędów.

Michael B.
źródło
Dla mnie $ jest nieco bardziej oczywiste niż \, aby zainicjować liczbę jako 0 w typie pieniężnym. YMMV
user1443098
5

Kompresja kodu za pomocą SQL

SQL jest trudny, osiąga wysokie wyniki i tak bardzo, jak go kochamy, SELECT FROM WHEREkosztuje 23 bajty przy każdym użyciu. Możesz skompresować te i inne powtarzające się słowa lub całe fragmenty kodu. Spowoduje to zmniejszenie kosztu krańcowego powtarzanego kodu do 1 bajtu! *

Jak to działa:

  • Zmienna jest deklarowana i przypisywana do skompresowanego kodu SQL
  • Tabela modyfikuje zmienną. Każdy wiersz opróżnia zmienną.
  • Zmodyfikowana zmienna jest wykonywana.

Problem:

Koszt początkowy wynosi prawie 100 bajtów, a każdy wiersz w tabeli wymiany kosztuje kolejne 6 bajtów. Tego rodzaju logika nie będzie bardzo skuteczna, chyba że pracujesz z dużą ilością kodu, którego nie można zmniejszyć lub wyzwanie jest oparte na kompresji.

Oto przykład

Wyzwanie polega na uzyskaniu ostatnich 10 wielokrotności 2,3 i 5 prowadzących do n. Powiedzmy, że to ( 343 bajty w golfa ) jest najlepszym rozwiązaniem, jakie mogłem wymyślić:

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

Przykład po skompresowaniu kodu

Wykonuje to ten sam kod, co powyżej, ma ~ 302 bajtów .

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)
comfortlydrei
źródło
Świetna strategia, że ​​styl wielokrotnego zastępowania może być również przydatny w bardziej konwencjonalnych scenariuszach.
BradC
1
Po kilku testach ustaliłem, że jeśli twoja lista zamienników zawiera 7 lub mniej elementów, możesz zaoszczędzić bajty, robiąc SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)zamiast używać pojedynczej kolumny z LEFT()i SUBSTRING(). Jeśli masz 8 lub więcej, unikanie dodatkowych cytatów i przecinków jest dobrym kompromisem.
BradC
Właściwie na 4 lub mniej zamienników, SET @=REPLACE(REPLACE(REPLACE(...
zapisałbyś
4

Oto zabawny. Spowoduje to przekształcenie wartości w kolumnie w jedną krotkę.

EDYCJA: Dziękuję za komentarze. Wygląda na to, że najkrótszym sposobem zwijania bez tagów XML jest:

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

Uwaga: jeśli XML jest prawidłowym wyjściem, możesz pominąć zewnętrzny wybór i parens. Również column1+'', działa tylko dla ciągów. W przypadku typów liczb najlepiej to zrobićcolumn1+0

comfortlydrei
źródło
1
Właściwie to wróci <column_name>value1</column_name><column_name>value2</column_name>.... Aby mieć plik CSV z kolumny, możesz DECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(dzięki za pierwszą wskazówkę @ MichaelB), który wróci value1,value2,.... Jednak w rzeczywistości jest on o 9 znaków dłuższy niż sztuczka XML :(
Jacob
1
Pamiętaj, że możesz to skrócić. Ltrimnie jest konieczne, ponieważ select (select ... for xml path ('')) zwraca an nvarchar(max). Ponadto, aby rozwiązać problem z kolumną, po prostu użyj niemutującego wyrażenia. W przypadku liczb można zrobić v+0, w przypadku łańcucha dodać pusty ciąg itp. Chociaż tak naprawdę nie uważam tego za wskazówkę golfową, jest to niestety rzeczywistość pisania zapytań na serwerze SQL.
Michael B
3

Możliwe jest użycie niektórych operatorów bitowych w T-SQL .

Nie mam konkretnego przykładu, ale uważam, że dobrze jest wiedzieć, kiedy gra się w golfa w T-SQL.

Jakub
źródło
1
To jest bardzo ważne. Zamiast pisać taki warunek x=0 or y=0, możesz napisać go jako logiczny odpowiednik, x|y=0który pozwala zaoszczędzić sporo bajtów!
Michael B
3

Drukuj zamiast Wybierz

To takie proste! Oto poliglota T-SQL / Python:

print'Hello, World!'

Wypróbuj online

mbomb007
źródło
3

Notacja naukowa jest krótszą metodą wyrażania bardzo dużych i bardzo małych liczb, np. select 1000000000= select 1E9I select 0.000001= select 1E-6.

naXa
źródło
2

Michael B wspomniał o użyciu rekurencyjnego CTE dla tabeli liczb , ale nie pokazał przykładu. Oto wersja MS-SQL, którą opracowaliśmy w tym innym wątku :

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

Pamiętaj, że możesz zmienić wartość początkową ( 1 n), interwał ( n + 1) i wartość końcową ( n < 99).

Jeśli potrzebujesz więcej niż 100 wierszy, musisz dodać option (maxrecursion 0):

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

lub dołącz do rCTE do siebie:

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

Chociaż ten ostatni nie gwarantuje zwrotu w kolejności numerycznej bez znaku ORDER BY 1

BradC
źródło
2

Użyj kompresji GZIP dla bardzo długich łańcuchów!

Wiedziałem więc, że SQL 2016 dodał COMPRESSfunkcję (i DECOMPRESSfunkcję), która (w końcu) daje możliwość GZIP-a łańcucha lub pliku binarnego.

Problem polega na tym, że nie jest od razu jasne, jak wykorzystać to do gry w golfa; COMPRESSmoże pobrać ciąg, ale zwraca a VARBINARY, który jest krótszy w bajtach (gdy jest przechowywany w VARBINARYpolu SQL ), ale jest dłuższy w znakach (nieprzetworzony hex).

Grałem z tym wcześniej, ale w końcu udało mi się stworzyć działającą wersję, opartą na starej odpowiedzi na SO . Ten post nie korzysta z nowych funkcji GZIP, ale konwertuje VARBINARYciąg znaków na kodowany w Base-64. Musieliśmy tylko wstawić nowe funkcje we właściwe miejsce i nieco poprawić grę.

Oto kod, którego można użyć do konwersji bardzo długiego ciągu na skompresowany ciąg zakodowany w standardzie 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))

Weź wynik i użyj go w kodzie zamiast oryginalnego długiego łańcucha wraz z:

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

Zamiast oryginalnego kodu ( 1471 bajtów )

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

miałbyś to ( 1034 bajty ):

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

Zobacz tę odpowiedź, która pozwoliła mi zaoszczędzić prawie 200 bajtów.

Nie zrobiłem matematyki, ale najwyraźniej z powodu narzutów będzie to skuteczne tylko w przypadku bardzo długich strun. Są prawdopodobnie inne miejsca, z których nie można korzystać; Już odkryłem, że musisz to SELECTzrobić, nie możesz tego PRINTzrobić, w przeciwnym razie otrzymasz:

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

EDYCJA : Krótsza wersja kodu dekompresyjnego, dzięki uprzejmości @digscoop :

Zaoszczędź 10 bajtów, zmieniając CASTkonwersję zewnętrzną na niejawną za pomocą CONCAT:

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

Możesz także zadeklarować zmienną typu XMLzamiast VARCHAR(MAX)i zapisać na wewnętrznej CAST:

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

Jest to nieco dłużej samo w sobie, ale jeśli potrzebujesz go w zmiennej z innych powodów, może to pomóc.

BradC
źródło
Fajnie, nie znam SQL, ale nadal wygląda fajnie
MilkyWay90,
1

Kilka przemyśleń na temat tworzenia i używania tabel do wyzwań:

1. Dane wejściowe SQL można pobrać z istniejącej tabeli

Metody wejścia / wyjścia Code Golf :

SQL może pobierać dane z nazwanej tabeli

Utworzenie i wypełnienie tej tabeli wartościami wejściowymi nie wlicza się do całkowitej liczby bajtów, możesz po prostu założyć, że już tam jest.

Oznacza to, że twoje obliczenia mogą być generowane przez prosty WYBÓR z tabeli wprowadzania:

SELECT 2*SQRT(a)FROM t

2. Jeśli to możliwe, w ogóle nie twórz tabeli

Zamiast (69 bajtów):

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

Po prostu zrób (43 bajty):

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

3. Jeśli to możliwe, utwórz tabelę przy pomocy WYBIERZ DO

Zamiast (39 bajtów):

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

Zrób to (17 bajtów):

SELECT 2 p INTO t

4: Rozważ połączenie wielu kolumn razem

Oto dwie odmiany, które zwracają ten sam wynik:

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)

Po niektórych testach górna wersja (wiele kolumn) wydaje się krótsza z 7 lub mniejszą liczbą wierszy , dolna wersja (z powodu LEWEJ i SUBSTRINGU) jest krótsza z 8 lub więcej wierszami . Twój przebieg może się różnić w zależności od dokładnych danych.

5: Użyj REPLACE i EXEC dla bardzo długich sekwencji tekstu

Zgodnie z doskonałą odpowiedzią komfortowo drei , jeśli masz 15 lub więcej wartości , użyj REPLACEsymbolu, aby pozbyć się powtarzających się '),('separatorów między elementami:

114 znaków:

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

112 znaków:

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

Jeśli używasz już dynamicznego SQL z innych powodów (lub masz wiele zamienników), to próg, w którym warto, jest znacznie niższy.

6: Użyj SELECT z nazwanymi kolumnami zamiast szeregu zmiennych

Zainspirowany doskonałą odpowiedzią jmlt tutaj , ponownie użyj ciągów znaków poprzez 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

zwroty

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

(W przypadku MS SQL zmieniłem \tzwrot na wbudowany i zmieniłem CONCAT()na +na zapisywanie bajtów).

BradC
źródło
1

Oznacz swój kod do podświetlania składni T-SQL

Zamiast po prostu:

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

Dołącz tag języka taki jak ten:

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

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

a wynikiem będzie:

CREATE TABLE t(b INT)
INSERT t VALUES(7),(14),(21),(99)
SELECT b FROM t
BradC
źródło
1

Skorzystaj z nowych funkcji / funkcji w MS SQL 2016 i SQL 2017

Jeśli nie masz kopii lokalnych do pracy, możesz grać online za pomocą StackExchange Data Explorer (SQL 2016) lub dbfiddle.uk (SQL 2016 lub SQL „vNext”).

STRING_SPLIT ( SQL 2016 i nowsze wersje )

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

Jeśli chcesz dokonać aliasu tabeli lub odwołać się do nazwy kolumny:

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

TRIM ( SQL 2017 lub nowszy )

Krótszy niż RTRIM()i na pewno krótszy niż LTRIM(RTRIM()).

Ma również opcję usuwania innych znaków lub zestawów znaków na początku lub na końcu:

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

zwroty L Server 2

TŁUMACZ ( SQL 2017 lub nowszy )

TRANSLATEpozwala zastąpić wiele znaków w jednym kroku, a nie kilka zagnieżdżonych REPLACEinstrukcji. Ale nie świętuj zbyt wiele, to zastępuje pojedyncze pojedyncze znaki różnymi pojedynczymi znakami.

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

Każdy znak w drugim ciągu jest zastępowany przez odpowiedni znak w 3 ciągu.

Wygląda na to, że moglibyśmy wyeliminować kilka postaci za pomocą czegoś takiego REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


Również niektóre bardziej interesujące, takie jak te CONCAT_WSi STRING_AGGktóre prawdopodobnie są warte obejrzenia.

BradC
źródło
1

Święta krowa, odkryłem cud PARSENAME( SQL 2012 lub wyższy ).

Funkcja została zbudowana w celu wyodrębnienia części nazwy obiektu jak servername.dbname.dbo.tablename, ale działa z dowolnymi wartościami oddzielonymi kropkami. Pamiętaj tylko, że liczy się od prawej , a nie lewej:

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

Jeśli masz mniej niż 4 wartości oddzielone kropkami, wróci NULLdo reszty (ale nadal liczy się od prawej do lewej ):

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

Tutaj jednak pojawia się magia: połącz ją z STRING_SPLIT(2016 lub nowszą wersją), aby stworzyć tabele wielokolumnowe w pamięci !!

Stare i zniszczone:

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

Nowa gorliwość:

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

Oczywiście twoje rzeczywiste oszczędności zależą od wielkości i zawartości tabeli oraz tego, jak dokładnie z niej korzystasz.

Zauważ, że jeśli twoje pola mają stałą szerokość, prawdopodobnie lepiej jest użyć LEFTi RIGHToddzielić je zamiast PARSENAME(nie tylko dlatego, że nazwy funkcji są krótsze, ale także dlatego, że możesz całkowicie wyeliminować separatory).

BradC
źródło
Nie jestem pewien, kiedy pojawiła się PARSENAME, ale są artykuły opisujące ją od 2003 r.
t-clausen.dk
1

Kilka innych niezwiązanych ze sobą sztuczek, które widziałem i chciałem zachować:

  1. Użyj, GO #aby powtórzyć blok określoną liczbę razy .

Widziałem tę sprytną sztuczkę na doskonałej odpowiedzi Paula .

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

Spowodowałoby to oczywiście zresetowanie wszystkich zmiennych przeciwnych w bloku, więc należałoby to porównać z WHILEpętlą lub x: ... GOTO xpętlą.

  1. SELECT TOP ... FROM systypes

Z tego samego pytania, co powyższe pytanie Paula, Anuj Tripathi zastosował następującą sztuczkę :

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

lub, jak sugeruje pinkfloydx33 w komentarzach:

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

Uwaga ta nie opiera się na żadnym z aktualnych treści o systypes, właśnie, że widok system istnieje (co robi w każdej bazie danych MS SQL) i zawiera co najmniej 10 wierszy (wygląda zawierać 34, dla najnowszych wersji SQL ). Nie mogłem znaleźć widoków systemu o krótszych nazwach (które nie wymagałyby sys.prefiksu), więc może to być idealne.

BradC
źródło
1

Zobacz to pytanie na dba.stackexchange aby uzyskać kilka interesujących pomysłów na dodanie kolumny liczb do wyniku STRING_SPLIT.

Biorąc pod uwagę ciąg 'one,two,three,four,five', chcemy uzyskać coś takiego:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. Odpowiedź, odpowiedź ROW_NUMBER()i zamówienie według Joe Obbisha NULLlub stała:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. Według odpowiedzi Paula White'a użyjSEQUENCE :

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

Sekwencje są interesującymi trwałymi obiektami; możesz zdefiniować typ danych, wartość minimalną i maksymalną, interwał oraz to, czy będzie się on owijał do początku:

    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. Za odpowiedź Biju Jose, można korzystać z IDENTITY() funkcji (co jest nie tak samo jak na IDENTITY nieruchomości w połączeniu z wkładką:

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

Pamiętaj, że dwa ostatnie parametry IDENTITY(INT,1,1)są opcjonalne i domyślnie wynoszą 1, jeśli zostaną wykluczone.

BradC
źródło
problem polega na tym, że STRING_SPLIT nie gwarantuje żadnego zamówienia zwrotnego. Możesz myśleć, że zawsze zwróci zestaw wierszy w kolejności tokenów w oryginalnym ciągu. Rzeczywiście może nawet to zrobić! Jednak nie ma gwarancji w dokumentach. w porządku, jeśli nie zależy ci na zamówieniu. Ale jeśli to zrobisz (np. Parsowanie wiersza w formacie CSV), wystąpi problem.
użytkownik1443098
1
@ user1443098 Ostatecznie zgadzam się z tobą w kontekście polecania kodu do celów biznesowych, jak możemy zobaczyć na dba.SE. Ale w przypadku wyzwań związanych z PPCG moje standardy są nieco inne; jeśli podczas testowania mój kod zwraca wiersze w żądanej kolejności, zapiszę bajty tam, gdzie mogę. Podobne do tego, jak pominie i ORDER BYczy uda mi się uciec (patrz na przykład moja odpowiedź na Toasty, Burnt, Brulee ).
BradC
1

Właśnie odkryłem, że możesz użyć cyfr dla pojedynczego znaku, REPLACEaby wyeliminować cudzysłowy :

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

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

To dlatego, że REPLACE z niejawnej konwersji na ciąg znaków.

Oba wytwarzają tę samą moc wyjściową:

Baby Shark doo doo doo doo doo doo
BradC
źródło
0

_ i # są poprawnymi aliasami. Używam ich z APLIKACJĄ KRZYŻOWĄ, aby wyglądało, że zwracane kolumny są częścią klauzuli FROM, np

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

Podoba mi się, gdy jedynym celem aplikacji CROSS APPLY jest obliczenie wyrażenia.

W tym przypadku użycie APPLY do obliczania podwyrażeń to fajny sposób na sprawienie, by Twój kod był OSUSZONY (i krótszy). Z tego, co widziałem w planach wykonania, takie podejście nie wiąże się z dodatkowymi kosztami. Kompilator odkrywa, że ​​po prostu coś obliczasz i traktuje to jak każde inne wyrażenie.

użytkownik1443098
źródło
Uważam, że krzyż stosuje się zbyt długo, naprawdę ciężko jest znaleźć użyteczną sytuację przy użyciu krzyżowania stosowania bez znalezienia innej krótszej metody
t-clausen.dk
OK - skróć przykład podany powyżej!
user1443098,
WYBIERZ TOP 10 numer, numer * 2 n2 Z master.dbo.spt_values ​​v
t-clausen.dk
Mam na myśli utrzymanie połączenia. Nawiasem mówiąc, po zbudowaniu zapytań XML, APLIKACJA KRZYŻOWA może stać się jedynym sposobem, aby to zrobić, ponieważ może nie być żadnych kolumn w podzapytaniu, które można łączyć.
user1443098,
Podselekcja jest krótsza niż zastosowanie krzyżowe: WYBIERZ top 10 * FROM (WYBIERZ numer n, numer * 2n2 FROM master..spt_values) x
t-clausen.dk