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. :)
Jawaban:
Trik umum saya ::
@
adalah variabel yang valid dalam t-sql.iif
pernyataan kasus gaya VB. Ini hampir selalu lebih pendek dari yang setaraif
else
.\
adalah cara yang berguna untuk menginisialisasi angka sebagai 0 dalam jenis uang. Anda bisa mengonversi nilai menjadi float dengan menambahkane
. misalnya4e
atau\k
yang akan menetapkan k ke nilai 0,00 uang.rCTE
tampaknya 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.;
.Select*from A,B where condition
lebih pendek dariselect*from A join b on condition
goto
loop 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 pertimbangkanconcat
fungsinya. Misal'hello'+str(@)
lebih pendek dariconcat('hello',@)
, tetapihello+str(@)+str(@a)
lebih panjang dariconcat('hello',@,@a)
Sebagai contoh, keduanya setara secara semantik.
Anda bisa menggunakan
Values
untuk membuat tabel atau subquery. Ini hanya akan benar-benar bermanfaat jika Anda membutuhkan beberapa baris konstan.sumber
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:
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:
Contoh setelah kode dikompresi
Ini mengeksekusi kode yang sama seperti di atas, ~ 302 byte golf .
sumber
SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)
alih - alih menggunakan satu kolom denganLEFT()
danSUBSTRING()
. Jika Anda memiliki 8 atau lebih, maka menghindari tanda kutip dan koma tambahan adalah pertukaran yang baik.SET @=REPLACE(REPLACE(REPLACE(...
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:
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
sumber
<column_name>value1</column_name><column_name>value2</column_name>...
. Untuk mendapatkan CSV dari kolom, Anda dapatDECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @
(terima kasih atas tip pertama @ MichaelB) yang akan kembalivalue1,value2,...
. Namun, sebenarnya 9 karakter lebih panjang dari trik XML Anda :(Ltrim
tidak diperlukan karena pilih (pilih ... untuk jalur xml ('')) mengembalikan sebuahnvarchar(max)
. Juga, untuk menyelesaikan masalah kolom cukup gunakan ekspresi yang tidak bermutasi. Untuk numerik yang dapat Anda lakukanv+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.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.
sumber
x=0 or y=0
, Anda dapat menulis itu sebagai setara secara logisx|y=0
yang menyimpan beberapa byte!Cetak bukan Pilih
Sesederhana itu! Jadi, inilah T-SQL / Python polyglot:
Cobalah online
sumber
Notasi ilmiah adalah metode yang lebih pendek untuk mengekspresikan angka yang sangat besar dan sangat kecil, misalnya
select 1000000000
=select 1E9
danselect 0.000001
=select 1E-6
.sumber
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 :
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)
:atau bergabung dengan rCTE untuk dirinya sendiri:
Meskipun yang terakhir ini tidak dijamin untuk kembali dalam urutan numerik tanpa
ORDER BY 1
sumber
Gunakan kompresi GZIP untuk string yang sangat panjang!
Jadi saya tahu bahwa SQL 2016 menambahkan
COMPRESS
fungsi (danDECOMPRESS
fungsi), yang (akhirnya) membawa kemampuan untuk GZIP string atau biner.Masalahnya adalah tidak segera jelas bagaimana memanfaatkan ini untuk bermain golf;
COMPRESS
dapat mengambil string tetapi mengembalikan aVARBINARY
, 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 a
VARBINARY
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:
Ambil output, dan gunakan dalam kode Anda menggantikan string panjang asli, bersama dengan:
Jadi, alih-alih kode asli Anda ( 1471 bytes )
Anda akan mendapatkan ini ( 1034 bytes ):
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 bisaPRINT
, kalau tidak Anda dapatkan:EDIT : Versi lebih pendek dari kode dekompresi, milik @digscoop :
Simpan 10 byte dengan mengubah bagian luar
CAST
ke konversi implisit menggunakanCONCAT
:Anda juga dapat mendeklarasikan variabel tipe
XML
bukanVARCHAR(MAX)
, dan menyimpan bagian dalamnyaCAST
:Ini sedikit lebih lama dengan sendirinya, tetapi jika Anda membutuhkannya dalam variabel untuk alasan lain, maka ini mungkin membantu.
sumber
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 :
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:
2. Jika memungkinkan, jangan membuat tabel sama sekali
Alih-alih (69 byte):
Lakukan (43 byte):
3. Jika memungkinkan, buat tabel dengan SELECT INTO
Alih-alih (39 byte):
Lakukan ini (17 byte):
4: Pertimbangkan menumbuk beberapa kolom bersamaan
Berikut adalah dua variasi yang mengembalikan output yang sama:
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
REPLACE
pada simbol untuk menyingkirkan'),('
pemisah berulang antara elemen:114 karakter:
112 karakter:
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:
kembali
(Untuk MS SQL saya mengubah
\t
ke pengembalian in-line, dan berubahCONCAT()
untuk+
menyelamatkan bytes).sumber
Tandai kode Anda untuk menyoroti sintaksis T-SQL
Alih-alih hanya:
Sertakan tag bahasa seperti ini:
dan hasilnya adalah:
sumber
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 )
Jika Anda perlu alias tabel atau merujuk ke nama kolom:
TRIM ( SQL 2017 atau lebih baru )
Lebih pendek dari
RTRIM()
dan tentu saja lebih pendek dariLTRIM(RTRIM())
.Juga memiliki opsi untuk menghapus karakter lain atau set karakter dari awal atau akhir:
kembali
L Server 2
TRANSLATE ( SQL 2017 atau lebih baru )
TRANSLATE
memungkinkan Anda untuk mengganti beberapa karakter dalam satu langkah, bukan sekelompokREPLACE
pernyataan bersarang . Tapi jangan terlalu banyak merayakan , itu hanya mengganti karakter tunggal individu dengan karakter tunggal berbeda.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_WS
danSTRING_AGG
yang mungkin patut dilihat juga.sumber
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:Jika Anda memiliki kurang dari 4 nilai yang dipisahkan titik, itu akan kembali
NULL
untuk sisanya (tetapi masih dihitung dari kanan ke kiri ):Di sinilah keajaibannya masuk: gabungkan dengan
STRING_SPLIT
(2016 atau lebih tinggi) untuk membuat tabel multi-kolom di dalam memori !!Tua dan rusak:
Hotness baru:
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
LEFT
danRIGHT
memisahkannya daripadaPARSENAME
(bukan hanya karena nama fungsi lebih pendek, tetapi juga karena Anda dapat menghilangkan pemisah sepenuhnya).sumber
Beberapa lagi trik yang tidak berhubungan yang saya lihat dan ingin saya pertahankan:
GO #
untuk mengulangi blok beberapa kali tertentu .Lihatlah trik cerdas ini pada jawaban Paul yang sangat bagus .
Ini tentu saja akan mengatur ulang variabel penghitung di blok, jadi Anda harus menimbang ini terhadap satu
WHILE
lingkaran atau satux: ... GOTO x
lingkaran.SELECT TOP ... FROM systypes
Dari pertanyaan yang sama dengan pertanyaan Paul di atas, Anuj Tripathi menggunakan trik berikut :
atau, seperti yang disarankan oleh pinkfloydx33 dalam komentar:
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 memerlukansys.
awalan), jadi ini mungkin ideal.sumber
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:Per Joe Obbish menjawab, menggunakan
ROW_NUMBER()
dan memesan olehNULL
atau konstanta:Per jawaban Paul White, gunakan
SEQUENCE
:Urutan adalah objek persisten yang menarik; Anda dapat menentukan tipe data, nilai min dan maks, interval, dan apakah itu melingkupi ke awal:
Per jawaban Biju jose, Anda dapat menggunakan yang
IDENTITY()
fungsi (yang tidak sama dengan yangIDENTITY
properti dalam hubungannya dengan INSERT:Perhatikan bahwa dua parameter terakhir
IDENTITY(INT,1,1)
adalah opsional, dan akan default ke 1 jika dikecualikan.sumber
ORDER BY
jika saya bisa lolos dengan itu (lihat jawaban saya untuk Toasty, Burnt, Brulee , misalnya).Baru diketahui bahwa Anda dapat menggunakan angka untuk satu karakter
REPLACE
untuk menghilangkan tanda kutip :Ini karena
REPLACE
melakukan konversi implisit ke string.Keduanya menghasilkan output yang sama:
sumber
_ dan # adalah alias yang valid. Saya menggunakannya dengan CROSS BERLAKU untuk membuatnya tampak kolom itu kembali adalah bagian dari klausa DARI misalnya
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.
sumber