T-SQL'de Golf İçin İpuçları


16

T-SQL'de golf oynamak için hangi genel ipuçlarınız var? Ben genel olarak en azından biraz T-SQL özgü olan golf sorunlarına kod uygulanabilir fikirler arıyorum. Lütfen cevap başına bir ipucu gönderin.

Orijinal fikir için Marcog'a teşekkürler. :)


bir ipucu - golf için farklı bir dil kullanın. Sql cevapları genellikle çok az veya hiç yok olur.
t-clausen.dk

Yanıtlar:


16

Genel hileler çantam ::

  • @ t-sql içinde geçerli bir değişkendir.
  • T-sql 2012, iifbir VB tarzı vaka ifadesi ekledi . Bu neredeyse her zaman eşdeğerden daha kısadır if else.
  • \para türünde bir sayıyı 0 olarak başlatmak için kullanışlı bir yöntemdir. Ekleyerek bir değeri kayan noktaya dönüştürebilirsiniz e. mesela 4eya \khangi değeri 0.00 para k ayarlayacaktır.
  • rCTE100 girişten daha az bir sayı tablosu oluşturmanın en iyi yolu gibi görünüyor. Spt_values ​​kullanmaktan bile daha kısa. 100'den fazlasına ihtiyacınız varsa, çapraz birleştirin ve ekleyin.
  • += ve diğer bileşik operatörleri 2008 yılında eklendi.
  • Değişmez değerler genellikle takma adlar için yeterince iyi bir sınırlayıcıdır. Nadiren bir boşluğa veya bir alana ihtiyacınız vardır ;.
  • İhtiyacınız olursa ANSI SQL birleşimlerini kullanın. Select*from A,B where conditiondaha kısaselect*from A join b on condition
  • While döngünüzün ilk yinelemeyi yapacağından emin olabilirseniz, bunu bir do-while tarzı gotodöngüsü olarak yeniden yazmak en iyisidir .
  • STR()int öğesini dizgeye dönüştüren en kısa işlevdir. Birden fazla dönüşüm yapıyorsanız veya çok sayıda farklı veri tipini birleştirmeniz gerekiyorsa bu concatişlevi göz önünde bulundurun . Örneğin 'hello'+str(@), daha kısa concat('hello',@), ancak hello+str(@)+str(@a)daha uzunconcat('hello',@,@a)

Örneğin, bu ikisi anlamsal olarak eşdeğerdir.

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

ValuesBir tablo veya alt sorgu oluşturmak için kullanabilirsiniz . Bu, yalnızca birkaç sabit satıra ihtiyacınız varsa gerçekten yararlı olacaktır.


Benim için $, para türünde bir sayıyı 0 olarak başlatmak için \ 'den biraz daha açıktır. YMMV
user1443098

5

SQL kullanarak kod sıkıştırma

SQL garip, yüksek puanlar ve sevdiğimiz kadarıyla, SELECT FROM WHEREher kullanımda 23 bayt maliyeti. Bunları ve diğer tekrarlanan kelimeleri veya tüm kod snippet'lerini sıkıştırabilirsiniz. Bunu yapmak, tekrarlanan kodun marjinal maliyetini 1 bayta düşürür! *

Bu nasıl çalışır:

  • Bir değişken bildirilir ve sıkıştırılmış SQL kodu atanır
  • Bir tablo değişkeni değiştirir. Her satır değişkeni tanımlar.
  • Değiştirilen değişken yürütülür.

Sorun:

Başlangıç ​​maliyeti 100 bayta yakındır ve değiştirme tablosundaki her satırın 6 bayt daha maliyeti vardır. Bu tür bir mantık, kesemeyeceğiniz çok fazla kodla çalışmadığınız veya zorluk sıkıştırma tabanlı olmadığı sürece çok etkili olmayacaktır.

İşte bir örnek

Zorluk, 2,3 ve 5'in son 10 katını n'ye çıkarmaktır. Diyelim ki ( 343 bayt golf ) gelebileceğim en iyi çözüm:

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

Kod sıkıştırıldıktan sonra örnek

Bu yukarıdaki ile aynı kodu yürütür, ~ 302 bayt 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)

Büyük strateji, çoklu değiştirme stili daha geleneksel senaryolarda da yararlı olabilir.
BradC

1
Bazı testlerden sonra, değiştirme listenizde 7 veya daha az öğe varsa SELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j), LEFT()ve ile tek bir sütun kullanmak yerine bayt kaydedeceğinizi belirledim SUBSTRING(). 8 veya daha fazlasına sahipseniz, ekstra tırnak ve virgüllerden kaçınmak iyi bir ödün vermektir.
BradC

Aslında 4 veya daha az değiştirme için, baytları eski moda bir şekilde SET @=REPLACE(REPLACE(REPLACE(...
kaydedersiniz

4

İşte komik olan. Bu, bir sütundaki değerleri tek bir gruba dönüştürür.

EDIT: Yorumlar için teşekkür ederim. XML etiketleri olmadan toplamanın en kısa yolu şöyledir:

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

Not: XML geçerli bir çıktıysa, dış seçimi ve parenleri atlayabilirsiniz. Ayrıca column1+'', yalnızca dizeler için çalışır. Sayı türleri için yapmak en iyisidircolumn1+0


1
Aslında geri dönecek <column_name>value1</column_name><column_name>value2</column_name>.... Bir sütundan bir CSV'ye sahip olmak için DECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(@ MichaelB'nin ilk ipucu için teşekkürler) geri dönebilirsiniz value1,value2,.... Ancak, aslında XML hilenizden 9 karakter daha uzun :(
Jacob

1
Bunu daha kısa yapabileceğinizi unutmayın. Ltrimselect (xml path ('') için select ... seçeneğini seçin) bir döndürdüğü için gerekli değildir nvarchar(max). Ayrıca, sütun şeyi çözmek için sadece mutasyona uğramayan bir ifade kullanın. Yapabileceğiniz sayısallar v+0için, dize boş dize vb ekleyin. Gerçekten bu bir golf ipucu düşünmese de, bu ne yazık ki sql sunucusunda sorgu yazma nasıl bir gerçeklik.
Michael B

3

T-SQL'de bazı bitsel operatörler kullanmak mümkündür .

Somut bir örneğim yok, ama T-SQL'de golf yaparken iyi bilinen bir gerçek olduğuna inanıyorum.


1
Bu çok geçerli. Bunun gibi bir durum x=0 or y=0yazmak yerine , bunu x|y=0birkaç bayt tasarruf eden mantıksal olarak eşdeğer olarak yazabilirsiniz !
Michael B


3

Bilimsel gösterim çok büyük ve çok küçük sayıları ifade etmek için daha kısa bir yöntemdir, örneğin select 1000000000= select 1E9ve select 0.000001= select 1E-6.


2

Michael B, bir sayı tablosu için özyinelemeli bir CTE kullandığından bahsetti , ancak bir örnek göstermedi. İşte bu diğer iş parçacığında çalıştığımız bir MS-SQL sürümü :

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

Not değişebileceğini başlayan değeri ( 1 n), aralık ( n + 1) ve bitiş değeri ( n < 99).

Yine de 100'den fazla satıra ihtiyacınız varsa şunları eklemeniz gerekir option (maxrecursion 0):

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

veya rCTE'ye kendiniz katılın:

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

Her ne kadar bu sonuncunun sayısal sırada döneceği garanti edilmese de ORDER BY 1


2

Çok uzun dizeler için GZIP sıkıştırmasını kullanın!

Bu yüzden SQL 2016'nın bir COMPRESSişlev (ve bir DECOMPRESSişlev) eklediğini biliyordum (sonunda) bir dize veya ikili GZIP yeteneği getiriyor.

Sorun şu ki, golf için bundan nasıl yararlanacağı hemen belli değil; COMPRESSbir dize alabilir ancak bayt cinsindenVARBINARY daha kısa (SQL alanında saklandığında ), ancak karakterlerde (ham onaltılık) daha uzun olan a değerini döndürür .VARBINARY

Daha önce bununla oynadım, ama sonunda SO'nun bu eski cevabına dayanan çalışan bir versiyon oluşturabiliyordum . Bu yazı yeni GZIP işlevlerini kullanmaz, ancak a'yı VARBINARYBase-64 kodlu dizeye dönüştürür. Sadece yeni fonksiyonları doğru yere yerleştirip biraz golf oynamaya ihtiyacımız vardı.

Çok uzun dizenizi Base-64 kodlu sıkıştırılmış dizeye dönüştürmek için kullanabileceğiniz kod:

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

Çıkışı alın ve orijinal uzun dizenin yerine kodunuzda kullanın:

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

Orijinal kodunuz yerine ( 1471 bayt )

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

buna sahip olursunuz ( 1034 bayt ):

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

Bana yaklaşık 200 baytlık tasarruf sağlayan bu cevaba bakın .

Matematiği yapmadım, ama açıkça tepegöz nedeniyle bu sadece çok uzun dizeler için etkili olacak. Muhtemelen bunun kullanılamayacağı başka yerler de vardır; Zaten SELECTbuna sahip olduğunu keşfettim , yapamazsın PRINT, aksi takdirde şunu elde edersin:

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

DÜZENLEME : Sıkıştırılmış kodun kısa sürümü , @digscoop'un izniyle :

Dış CASTyüzeyi örtük bir dönüştürmeye dönüştürerek 10 bayt tasarruf edin CONCAT:

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

Ayrıca , XMLyerine bir tür değişkeni bildirebilir VARCHAR(MAX)ve iç kısma kaydedebilirsiniz CAST:

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

Bu kendi başına biraz daha uzundur, ancak başka nedenlerle bir değişkene ihtiyacınız varsa, yardımcı olabilir.


Güzel, SQL bilmiyorum ama bu hala harika görünüyor
MilkyWay90

1

Zorluklar için tablolar oluşturma ve kullanma hakkında birkaç düşünce:

1. SQL girişi önceden var olan bir tablo ile alınabilir

Kod Golf Giriş / Çıkış Yöntemleri :

SQL'ler adlandırılmış bir tablodan girdi alabilir

Bu tabloyu giriş değerleri ile oluşturmak ve doldurmak bayt toplamınıza dahil değildir, sadece orada olduğunu varsayabilirsiniz.

Bu, hesaplamalarınızın giriş tablosundan basit SELECT üzerinden çıktı alabileceği anlamına gelir:

SELECT 2*SQRT(a)FROM t

2. Mümkünse, aslında bir tablo oluşturmayın

(69 bayt) yerine:

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

Sadece yapın (43 bayt):

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

3. Mümkünse, SELECT INTO ile tablo oluşturun

(39 bayt) yerine:

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

Bunu yapın (17 bayt):

SELECT 2 p INTO t

4: Birden çok sütunu bir araya getirmeyi düşünün

Aynı çıktıyı döndüren iki varyasyon:

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)

Bazı testlerden sonra, üst sürüm (birden çok sütun) 7 veya daha az satırla daha kısa görünür , alt sürüm (SOL ve SUBSTRING nedeniyle) 8 veya daha fazla satırla daha kısadır . Kilometreniz, kesin verilerinize bağlı olarak değişebilir.

5: Çok uzun metin dizileri için REPLACE ve EXEC kullanın

Konforlu bir şekilde drei'nin mükemmel cevabında , 15 veya daha fazla değeriniz varsa , öğeler arasındaki REPLACEtekrarlanan '),('ayırıcılardan kurtulmak için bir sembol kullanın :

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

Eğer ediyorsanız zaten başka nedenlerle dinamik SQL kullanarak (ya da birden yerine geçer var), bu değer o eşik çok düşüktür.

6: Çok sayıda değişken yerine adlandırılmış sütunlarla bir SELECT kullanın

Burada jmlt'ın mükemmel cevabından esinlenerek , SELECT aracılığıyla dizeleri tekrar kullanın:

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

İadeler

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

(MS SQL Değiştim için \tbir in-line iade etmek ve değiştirilen CONCAT()için +bayt kaydetmek için).


1

Kodunuzu T-SQL sözdizimi vurgulaması için etiketleme

Sadece yerine:

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

Bunun gibi bir dil etiketi ekleyin:

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

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

ve sonuç:

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

1

MS SQL 2016 ve SQL 2017'deki yeni özelliklerden / işlevlerden yararlanın

Çalışacak yerel kopyalarınız yoksa, StackExchange Veri Gezgini (SQL 2016) veya dbfiddle.uk (SQL 2016 veya SQL " vNext ") ile çevrimiçi oynayabilirsiniz .

STRING_SPLIT ( SQL 2016 ve üstü )

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

Tabloyu diğer adı takmanız veya sütun adına başvurmanız gerekiyorsa:

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

TRIM ( SQL 2017 veya üzeri )

Daha kısa RTRIM()ve kesinlikle daha kısa LTRIM(RTRIM()).

Ayrıca diğer karakterleri veya karakter kümelerini baştan veya sondan kaldırma seçeneği vardır :

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

İadeler L Server 2

ÇEVİRİ ( SQL 2017 veya üstü )

TRANSLATEbir grup iç içe REPLACEifade yerine birden çok karakteri tek adımda değiştirmenize olanak tanır . Ancak çok fazla kutlama yapmayın , sadece tek tek karakterleri farklı tek karakterlerle değiştirir.

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

İkinci dizgideki her karakterin yerine 3. dizgideki karşılık gelen karakter gelir .

Görünüşe göre bir grup karakteri bir şeyle ortadan kaldırabiliriz REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


Bazı daha ilginç olanlar da, muhtemelen CONCAT_WSve STRING_AGGmuhtemelen bir göz atmaya değer.


1

Kutsal inek, merakını keşfettim PARSENAME( SQL 2012 veya üstü ).

Fonksiyonu gibi bir nesne adının parçaları izole etmek inşa edildi servername.dbname.dbo.tablename, ama bunun için çalışır herhangi nokta ayrılmış değerler. Sadece soldan değil, sağdan sayıldığını unutmayın :

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

4'ten az nokta ile ayrılmış değeriniz varsa, geri NULLkalanı için geri döner (ancak yine de sağdan sola sayılır ):

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

İşte sihir burada devreye giriyor: bellek içi çok sütunlu tablolarSTRING_SPLIT yapmak için onu (2016 veya daha yüksek) ile birleştirin !!

Eski ve baskın:

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

Yeni sıcaklık:

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

Açıkçası, gerçek tasarruflarınız tablonun boyutuna ve içeriğine ve onu tam olarak nasıl kullandığınıza bağlıdır.

Senin alanlar sabit genişlikli ise, kullandığınız muhtemelen daha çok işinize geldiğini hatırlatırız LEFTve RIGHTyerine onları ayırmak için PARSENAME(sadece işlev isimleri kısadır çünkü, aynı zamanda tamamen ayırıcılar ortadan kaldırabilir çünkü).


PARSENAME'in ne zaman ortaya çıktığından emin değilim, ancak 2003'ten itibaren açıklayan makaleler var
t-clausen.dk

1

Gördüğüm ve korumak istediğim birkaç daha ilgisiz hile:

  1. GO #Bir bloğu belirli sayıda tekrarlamak için kullanın .

Paul'un mükemmel cevabındaki bu akıllı numarayı gördüm .

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

Bu, elbette, bloktaki herhangi bir sayaç değişkenini sıfırlar, böylece bunu bir WHILEdöngüye veya döngüye karşı x: ... GOTO xtartmanız gerekir.

  1. SELECT TOP ... FROM systypes

Paul'un yukarıdaki ile aynı sorudan Anuj Tripathi şu hileyi kullandı :

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

veya yorumlarda pinkfloydx33 tarafından önerildiği gibi:

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

Bu fiili herhangi dayanmaz Not içeriklerin ait systypessistem görünümü en az 10 satır (her MS SQL veritabanında yapar) var ve içerdiği sadece, (o SQL en son sürümleri için, 34 içerecek şekilde görünüyor ). (Bir sys.önek gerektirmeyen ) daha kısa adlarla herhangi bir sistem görünümü bulamadım , bu yüzden bu ideal olabilir.


1

Bir STRING_SPLIT sonucuna sayı sütunu eklemek için bazı ilginç fikirler için dba.stackexchange'te bu soruya bakın .

Gibi bir dize verildiğinde 'one,two,three,four,five', şöyle bir şey almak istiyoruz:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. Joe Obbish'in cevabı, kullanımı ROW_NUMBER()ve NULLbir sabit ile:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. Paul White'ın cevabı başına, SEQUENCE şunları kullanın :

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

Diziler ilginç kalıcı nesnelerdir; veri türünü, min ve maks değerini, aralığı ve başlangıca dolanıp sarılmayacağını tanımlayabilirsiniz:

    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. Biju jose Yanıt başına kullanabileceğiniz işlevi olduğu ( değil aynı özelliğiIDENTITY() IDENTITY bir INSERT ile birlikte:

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

İçindeki son iki parametrenin IDENTITY(INT,1,1)isteğe bağlı olduğunu ve hariç tutulduğunda varsayılan olarak 1 olacağını unutmayın.


sorun şu ki, STRING_SPLIT herhangi bir iade emrini garanti etmiyor. Satır kümesini her zaman orijinal dizedeki belirteçlerin sırasına göre döndüreceğini düşünebilirsiniz. Hatta bunu bile yapabilir! Ancak dokümanlarda garanti yoktur. Eğer sipariş umurumda değil. Ancak bunu yaparsanız (örn. CSV biçiminde bir satırı ayrıştırma) bir sorun vardır.
user1443098

1
@ user1443098 nihayetinde, dba.SE'de görebileceğimiz gibi, iş amaçlı kod önerme bağlamında sizinle aynı fikirdeyim. Ancak PPCG'deki zorluklar için standartlarım biraz farklı; Eğer test benim kodları istediğim sıraya göre döndürürse, o zaman yapabileceğim baytları kaydedeceğim. Bir ORDER BYşeyi dışarıda bırakabileceğim gibi bırakacağım gibi ( örneğin Toasty, Burnt, Brulee'ye cevabım bakın ).
BradC

1

Tırnak işaretlerini ortadan kaldırmak için tek bir karakter için rakamları kullanabileceğinizi keşfettikREPLACE :

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

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

Bunun nedeni REPLACE, dizeye örtük bir dönüşüm yapılmasıdır.

Her ikisi de aynı çıktıyı üretir:

Baby Shark doo doo doo doo doo doo

0

_ ve # geçerli takma adlardır. Onları CROSS APPLY ile birlikte döndürdüğümde döndürdüğü sütunlar FROM yan tümcesinin bir parçasıdır.

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

ÇAPRAZ UYGULAMA'nın tek amacı bir ifade hesaplamak olduğunda bunu sevdim.

Bu nedenle, alt ifadeleri hesaplamak için APPLY kullanmak, kodunuzu DRY-er (ve daha kısa) yapmak için temiz bir yoldur. İnfaz planlarında gördüğüm kadarıyla, bu yaklaşıma ek bir maliyet yoktur. Derleyici sadece bir şey hesapladığınızı ve başka herhangi bir ifade gibi davrandığınızı anlar.


Çapraz uygulama uzun süre için bulmak, başka bir kısa yöntem bulmadan çapraz uygulama kullanarak yararlı bir durum bulmak gerçekten zor
t-clausen.dk

Tamam - yukarıda verilen örneği kısaltın!
user1443098

SEÇ 10 numara, sayı * 2 n2
BAŞLANGIÇ

Demek istediğim, birleşmeyi sürdürmek. Bu arada, xml sorguları oluşturduğunuzda, CROSS APPLY bunu yapmanın tek yolu olabilir, çünkü bir alt sorguda birleştirme yapmak için hiçbir sütun bulunmayabilir.
user1443098

Alt seçim çapraz uygulamadan daha kısa: SELECT top 10 * FROM (SELECT sayı n, sayı *
2n2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.