Kiat Golf di T-SQL


16

Apa tips umum yang Anda miliki untuk bermain golf di T-SQL? Saya mencari ide yang dapat diterapkan pada masalah kode golf secara umum yang setidaknya agak spesifik untuk T-SQL. Silakan kirim satu tip per jawaban.

Terima kasih kepada Marcog untuk ide aslinya. :)


tip - gunakan bahasa yang berbeda untuk bermain golf. Jawaban Sql biasanya mendapat sangat sedikit atau tidak ada peningkatan sama sekali.
t-clausen.dk

Jawaban:


16

Trik umum saya ::

  • @ adalah variabel yang valid dalam t-sql.
  • T-sql 2012 menambahkan iifpernyataan kasus gaya VB. Ini hampir selalu lebih pendek dari yang setara if else.
  • \adalah cara yang berguna untuk menginisialisasi angka sebagai 0 dalam jenis uang. Anda bisa mengonversi nilai menjadi float dengan menambahkan e. misalnya 4eatau \kyang akan menetapkan k ke nilai 0,00 uang.
  • rCTEtampaknya menjadi cara terbaik untuk membuat tabel angka kurang dari 100 entri. Bahkan lebih pendek daripada menggunakan spt_values. Jika Anda membutuhkan lebih dari 100, silang bergabung dan tambahkan.
  • += dan operator gabungan lainnya ditambahkan pada tahun 2008. Gunakan mereka menghemat beberapa karakter.
  • Literal biasanya pembatas yang cukup baik untuk tujuan aliasing. Anda jarang membutuhkan ruang atau ;.
  • Gunakan gabungan ANSI SQL jika Anda membutuhkannya. Select*from A,B where conditionlebih pendek dariselect*from A join b on condition
  • Jika Anda yakin bahwa loop sementara Anda akan melakukan iterasi pertama, lebih baik menulisnya sebagai gotoloop gaya do-while .
  • STR()adalah fungsi terpendek untuk mengubah int menjadi string. Jika Anda melakukan lebih dari satu konversi atau mungkin perlu melakukan concat berbagai tipe data pertimbangkan concatfungsinya. Misal 'hello'+str(@)lebih pendek dari concat('hello',@), tetapi hello+str(@)+str(@a)lebih panjang dariconcat('hello',@,@a)

Sebagai contoh, keduanya setara secara semantik.

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

Anda bisa menggunakan Valuesuntuk membuat tabel atau subquery. Ini hanya akan benar-benar bermanfaat jika Anda membutuhkan beberapa baris konstan.


Bagi saya, $ sedikit lebih jelas daripada \ untuk menginisialisasi angka sebagai 0 dalam jenis uang. YMMV
user1443098

5

Kompresi kode menggunakan SQL

SQL bertele-tele, skor tinggi, dan sebanyak yang kita suka, SELECT FROM WHERE harganya 23 byte setiap kali digunakan. Anda dapat memampatkan ini dan kata-kata berulang lainnya atau seluruh potongan kode. Melakukan ini akan mengurangi biaya marginal dari kode yang diulang menjadi 1 byte! *

Bagaimana ini bekerja:

  • Variabel dideklarasikan dan ditugaskan kode SQL terkompresi
  • Tabel memodifikasi variabel. Setiap baris mengempiskan variabel.
  • Variabel yang dimodifikasi dieksekusi.

Masalah:

Biaya dimuka dekat dengan 100 byte dan setiap baris dalam tabel penggantian biaya 6 byte lainnya. Jenis logika ini tidak akan sangat efektif kecuali jika Anda bekerja dengan banyak kode yang tidak dapat Anda kurangi atau tantangannya berbasis kompresi.

Ini sebuah contoh

Tantangannya adalah untuk mendapatkan 10 kelipatan 2,3, dan 5 menuju n. Katakanlah ini ( 343 byte golf ) adalah solusi terbaik yang dapat saya berikan:

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

Contoh setelah kode dikompresi

Ini mengeksekusi kode yang sama seperti di atas, ~ 302 byte golf .

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)

Strategi hebat, gaya multi-ganti dapat berguna dalam skenario yang lebih konvensional juga.
BradC

1
Setelah beberapa pengujian, saya telah menentukan bahwa jika daftar pengganti Anda memiliki 7 atau lebih sedikit item, Anda akan menghemat byte dengan melakukan SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)alih - alih menggunakan satu kolom dengan LEFT()dan SUBSTRING(). Jika Anda memiliki 8 atau lebih, maka menghindari tanda kutip dan koma tambahan adalah pertukaran yang baik.
BradC

Sebenarnya untuk penggantian 4 atau lebih sedikit, Anda akan menghemat byte dengan kunoSET @=REPLACE(REPLACE(REPLACE(...
BradC

4

Ini yang lucu. Ini akan mengonversi nilai dalam kolom menjadi satu tupel.

EDIT: Terima kasih atas komentarnya. Sepertinya cara terpendek untuk menggulung tanpa tag XML adalah:

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

Catatan: jika XML adalah output yang valid, Anda dapat menghilangkan pemilihan luar dan parens. Juga column1+'', hanya berfungsi untuk string. Untuk jenis nomor yang paling baik dilakukancolumn1+0


1
Sebenarnya itu akan kembali <column_name>value1</column_name><column_name>value2</column_name>.... Untuk mendapatkan CSV dari kolom, Anda dapat DECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(terima kasih atas tip pertama @ MichaelB) yang akan kembali value1,value2,.... Namun, sebenarnya 9 karakter lebih panjang dari trik XML Anda :(
Yakub

1
Catatan Anda dapat membuat ini lebih pendek. Ltrimtidak diperlukan karena pilih (pilih ... untuk jalur xml ('')) mengembalikan sebuah nvarchar(max). Juga, untuk menyelesaikan masalah kolom cukup gunakan ekspresi yang tidak bermutasi. Untuk numerik yang dapat Anda lakukan v+0, untuk string tambahkan string kosong dll. Meskipun saya tidak benar-benar menganggap ini tip golf, ini hanya sayangnya kenyataan bagaimana menulis query di sql server.
Michael B

3

Dimungkinkan untuk menggunakan beberapa operator bitwise di T-SQL .

Saya tidak punya contoh nyata, tapi saya percaya itu adalah fakta yang baik untuk diketahui ketika bermain golf di T-SQL.


1
Ini sangat valid. Alih-alih menulis kondisi seperti x=0 or y=0, Anda dapat menulis itu sebagai setara secara logis x|y=0yang menyimpan beberapa byte!
Michael B


3

Notasi ilmiah adalah metode yang lebih pendek untuk mengekspresikan angka yang sangat besar dan sangat kecil, misalnya select 1000000000= select 1E9dan select 0.000001= select 1E-6.


2

Michael B disebutkan menggunakan CTE rekursif untuk tabel angka , tetapi tidak menunjukkan contoh. Berikut adalah versi MS-SQL yang kami kerjakan di utas lainnya ini :

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

Perhatikan bahwa Anda dapat mengubah nilai awal ( 1 n), interval ( n + 1) dan nilai akhir ( n < 99).

Jika Anda membutuhkan lebih dari 100 baris, Anda harus menambahkan option (maxrecursion 0):

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

atau bergabung dengan rCTE untuk dirinya sendiri:

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

Meskipun yang terakhir ini tidak dijamin untuk kembali dalam urutan numerik tanpa ORDER BY 1


2

Gunakan kompresi GZIP untuk string yang sangat panjang!

Jadi saya tahu bahwa SQL 2016 menambahkan COMPRESS fungsi (dan DECOMPRESSfungsi), yang (akhirnya) membawa kemampuan untuk GZIP string atau biner.

Masalahnya adalah tidak segera jelas bagaimana memanfaatkan ini untuk bermain golf; COMPRESSdapat mengambil string tetapi mengembalikan a VARBINARY, yang lebih pendek dalam byte (bila disimpan dalam SQLVARBINARY bidang ), tetapi lebih panjang dalam karakter (hex mentah).

Saya sudah pernah bermain dengan ini sebelumnya, tapi akhirnya saya bisa membuat versi yang berfungsi, berdasarkan jawaban lama ini di SO . Posting itu tidak menggunakan fungsi GZIP baru, tetapi ia mengonversi aVARBINARY ke string yang dikodekan Base-64. Kami hanya perlu memasukkan fungsi-fungsi baru ke tempat yang tepat, dan sedikit golf itu.

Berikut adalah kode yang dapat Anda gunakan untuk mengonversi string Anda yang sangat panjang menjadi string terkompresi Base-64 yang dikodekan:

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

Ambil output, dan gunakan dalam kode Anda menggantikan string panjang asli, bersama dengan:

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

Jadi, alih-alih kode asli Anda ( 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.'

Anda akan mendapatkan ini ( 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))

Lihat jawaban ini yang menyelamatkan saya hampir 200 byte.

Saya belum melakukan matematika, tetapi jelas karena overhead ini hanya akan efektif untuk string yang sangat panjang. Mungkin ada tempat lain yang tidak bisa digunakan; Saya sudah menemukan Anda harus melakukannya SELECT, Anda tidak bisa PRINT, kalau tidak Anda dapatkan:

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

EDIT : Versi lebih pendek dari kode dekompresi, milik @digscoop :

Simpan 10 byte dengan mengubah bagian luar CASTke konversi implisit menggunakan CONCAT:

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

Anda juga dapat mendeklarasikan variabel tipe XMLbukan VARCHAR(MAX), dan menyimpan bagian dalamnya CAST:

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

Ini sedikit lebih lama dengan sendirinya, tetapi jika Anda membutuhkannya dalam variabel untuk alasan lain, maka ini mungkin membantu.


Bagus, saya tidak tahu SQL tetapi ini masih terlihat keren
MilkyWay90

1

Beberapa pemikiran tentang membuat dan menggunakan tabel untuk tantangan:

1. Masukan SQL dapat diambil melalui tabel yang sudah ada sebelumnya

Metode Input / Output Golf Code :

SQL dapat mengambil input dari tabel bernama

Membuat dan mengisi tabel ini dengan nilai input tidak dihitung terhadap total byte Anda, Anda dapat mengasumsikan itu sudah ada.

Ini berarti perhitungan Anda dapat dikeluarkan melalui PILIH sederhana dari tabel input:

SELECT 2*SQRT(a)FROM t

2. Jika memungkinkan, jangan membuat tabel sama sekali

Alih-alih (69 byte):

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

Lakukan (43 byte):

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

3. Jika memungkinkan, buat tabel dengan SELECT INTO

Alih-alih (39 byte):

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

Lakukan ini (17 byte):

SELECT 2 p INTO t

4: Pertimbangkan menumbuk beberapa kolom bersamaan

Berikut adalah dua variasi yang mengembalikan output yang sama:

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)

Setelah beberapa pengujian, versi teratas (beberapa kolom) tampak lebih pendek dengan 7 atau lebih sedikit baris , versi bawah (karena LEFT dan SUBSTRING) lebih pendek dengan 8 baris atau lebih . Jarak tempuh Anda dapat bervariasi, tergantung pada data Anda yang sebenarnya.

5: Gunakan REPLACE dan EXEC untuk urutan teks yang sangat panjang

Di tengah jawaban yang sangat nyaman dengan nyaman , jika Anda memiliki 15 nilai atau lebih , gunakan REPLACEpada simbol untuk menyingkirkan '),('pemisah berulang antara elemen:

114 karakter:

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

112 karakter:

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

Jika sudah menggunakan SQL dinamis untuk alasan lain (atau memiliki beberapa pengganti), maka ambang di mana ini layak jauh lebih rendah.

6: Gunakan SELECT dengan kolom bernama daripada sekelompok variabel

Terinspirasi oleh jawaban jmlt yang sangat baik di sini , gunakan kembali string melalui 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

kembali

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

(Untuk MS SQL saya mengubah \tke pengembalian in-line, dan berubah CONCAT()untuk +menyelamatkan bytes).


1

Tandai kode Anda untuk menyoroti sintaksis T-SQL

Alih-alih hanya:

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

Sertakan tag bahasa seperti ini:

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

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

dan hasilnya adalah:

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

1

Manfaatkan fitur / fungsi baru di MS SQL 2016 dan SQL 2017

Jika Anda tidak memiliki salinan lokal untuk bekerja, Anda dapat bermain online dengan StackExchange Data Explorer (SQL 2016) atau dengan dbfiddle.uk (SQL 2016 atau SQL "vNext").

STRING_SPLIT ( SQL 2016 dan yang lebih baru )

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

Jika Anda perlu alias tabel atau merujuk ke nama kolom:

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

TRIM ( SQL 2017 atau lebih baru )

Lebih pendek dari RTRIM()dan tentu saja lebih pendek dari LTRIM(RTRIM()).

Juga memiliki opsi untuk menghapus karakter lain atau set karakter dari awal atau akhir:

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

kembali L Server 2

TRANSLATE ( SQL 2017 atau lebih baru )

TRANSLATEmemungkinkan Anda untuk mengganti beberapa karakter dalam satu langkah, bukan sekelompok REPLACEpernyataan bersarang . Tapi jangan terlalu banyak merayakan , itu hanya mengganti karakter tunggal individu dengan karakter tunggal berbeda.

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

Setiap karakter dalam string kedua digantikan oleh karakter yang sesuai di string ke-3.

Sepertinya kita bisa menghilangkan banyak karakter dengan sesuatu seperti REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


Beberapa yang lebih menarik juga, seperti CONCAT_WSdan STRING_AGGyang mungkin patut dilihat juga.


1

Astaga, saya telah menemukan keajaiban PARSENAME( SQL 2012 atau lebih tinggi ).

Fungsi ini dibangun untuk mengisolasi bagian-bagian dari nama objek seperti servername.dbname.dbo.tablename, tetapi berfungsi untuk setiap nilai yang dipisahkan titik. Ingat saja itu dihitung dari kanan , bukan kiri:

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

Jika Anda memiliki kurang dari 4 nilai yang dipisahkan titik, itu akan kembali NULLuntuk sisanya (tetapi masih dihitung dari kanan ke kiri ):

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

Di sinilah keajaibannya masuk: gabungkan dengan STRING_SPLIT(2016 atau lebih tinggi) untuk membuat tabel multi-kolom di dalam memori !!

Tua dan rusak:

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

Hotness baru:

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

Jelas penghematan Anda sebenarnya tergantung pada ukuran dan isi tabel, dan bagaimana tepatnya Anda menggunakannya.

Perhatikan bahwa jika bidang Anda lebar konstan, Anda mungkin lebih baik menggunakan LEFTdan RIGHTmemisahkannya daripada PARSENAME(bukan hanya karena nama fungsi lebih pendek, tetapi juga karena Anda dapat menghilangkan pemisah sepenuhnya).


Saya tidak yakin kapan PARSENAME keluar, tetapi ada artikel yang menggambarkannya mulai tahun 2003
t-clausen.dk

1

Beberapa lagi trik yang tidak berhubungan yang saya lihat dan ingin saya pertahankan:

  1. Gunakan GO #untuk mengulangi blok beberapa kali tertentu .

Lihatlah trik cerdas ini pada jawaban Paul yang sangat bagus .

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

Ini tentu saja akan mengatur ulang variabel penghitung di blok, jadi Anda harus menimbang ini terhadap satu WHILElingkaran atau satu x: ... GOTO xlingkaran.

  1. SELECT TOP ... FROM systypes

Dari pertanyaan yang sama dengan pertanyaan Paul di atas, Anuj Tripathi menggunakan trik berikut :

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

atau, seperti yang disarankan oleh pinkfloydx33 dalam komentar:

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

Catatan ini tidak bergantung pada salah satu yang sebenarnya isi dari systypes, hanya saja sistem pandangan ada (yang tidak di setiap database MS SQL), dan berisi setidaknya 10 baris (terlihat mengandung 34, untuk versi terbaru dari SQL ). Saya tidak dapat menemukan tampilan sistem dengan nama yang lebih pendek (yang tidak memerlukan sys.awalan), jadi ini mungkin ideal.


1

Lihat pertanyaan ini di dba.stackexchange untuk beberapa ide menarik untuk menambahkan kolom angka ke hasil STRING_SPLIT.

Diberikan string seperti 'one,two,three,four,five', kami ingin mendapatkan sesuatu seperti:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. Per Joe Obbish menjawab, menggunakan ROW_NUMBER()dan memesan oleh NULLatau konstanta:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. Per jawaban Paul White, gunakanSEQUENCE :

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

Urutan adalah objek persisten yang menarik; Anda dapat menentukan tipe data, nilai min dan maks, interval, dan apakah itu melingkupi ke awal:

    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 jawaban Biju jose, Anda dapat menggunakan yang IDENTITY() fungsi (yang tidak sama dengan yang IDENTITY properti dalam hubungannya dengan INSERT:

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

Perhatikan bahwa dua parameter terakhir IDENTITY(INT,1,1)adalah opsional, dan akan default ke 1 jika dikecualikan.


masalahnya adalah STRING_SPLIT tidak menjamin pesanan pengembalian. Anda mungkin berpikir itu akan selalu mengembalikan rowset sesuai urutan token di string asli. Bahkan mungkin bisa melakukan itu! Namun, tidak ada jaminan dalam dokumen. tidak apa-apa jika Anda tidak peduli dengan pesanan. Tetapi jika Anda melakukannya (misalnya mengurai baris dalam format CSV), ada masalah.
user1443098

1
@ user1443098 Saya akhirnya setuju dengan Anda dalam konteks merekomendasikan kode untuk tujuan bisnis, seperti yang mungkin kita lihat di dba.SE. Tetapi untuk tantangan pada PPCG standar saya agak berbeda; jika dalam pengujian kode saya mengembalikan baris dalam urutan yang saya inginkan maka saya akan menyimpan byte di mana saya bisa. Mirip dengan bagaimana saya akan meninggalkan ORDER BYjika saya bisa lolos dengan itu (lihat jawaban saya untuk Toasty, Burnt, Brulee , misalnya).
BradC

1

Baru diketahui bahwa Anda dapat menggunakan angka untuk satu karakter REPLACEuntuk menghilangkan tanda kutip :

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

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

Ini karena REPLACEmelakukan konversi implisit ke string.

Keduanya menghasilkan output yang sama:

Baby Shark doo doo doo doo doo doo

0

_ dan # adalah alias yang valid. Saya menggunakannya dengan CROSS BERLAKU untuk membuatnya tampak kolom itu kembali adalah bagian dari klausa DARI misalnya

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

Saya suka ini ketika satu-satunya tujuan CROSS BERLAKU adalah untuk menghitung ekspresi.

Untuk itu, menggunakan BERLAKU untuk menghitung sub-ekspresi adalah cara yang rapi untuk membuat kode Anda KERING-er (dan lebih pendek). Dari apa yang saya lihat dalam rencana pelaksanaan, tidak ada biaya tambahan untuk pendekatan ini. Compiler memperkirakan Anda hanya menghitung sesuatu dan memperlakukannya seperti ekspresi lainnya.


Saya menemukan cross berlaku untuk panjang, sangat sulit untuk menemukan situasi yang berguna menggunakan cross apply tanpa menemukan metode lain yang lebih pendek
t-clausen.dk

OK - persingkat contoh yang diberikan di atas!
user1443098

PILIH nomor TOP 10, nomor * 2 n2 DARI master.dbo.spt_values ​​v
t-clausen.dk

Maksudku, tetap bergabung. Ngomong-ngomong, setelah Anda membangun kueri xml, CROSS APPLY dapat menjadi satu-satunya cara untuk melakukannya, karena mungkin tidak ada kolom dalam subquery yang digabung.
user1443098

Subselect lebih pendek dari cross berlaku: SELECT top 10 * FROM (SELECT number n, number * 2n2 FROM master..spt_values) x
t-clausen.dk
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.