เคล็ดลับการตีกอล์ฟใน T-SQL


16

คุณมีเคล็ดลับทั่วไปอะไรสำหรับการเล่นกอล์ฟใน T-SQL ฉันกำลังมองหาแนวคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ T-SQL กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ

ขอบคุณ Marcog สำหรับแนวคิดดั้งเดิม :)


เคล็ดลับ - ใช้ภาษาอื่นในการเล่นกอล์ฟ คำตอบ SQL มักจะได้รับน้อยมากหรือไม่มี upvotes เลย
t-clausen.dk

คำตอบ:


16

กระเป๋าทั่วไปของฉันของเทคนิค ::

  • @ เป็นตัวแปรที่ถูกต้องใน t-sql
  • T-sql 2012 ได้เพิ่มiifคำสั่งกรณีสไตล์ VB if elseนี้มักจะสั้นกว่าเทียบเท่า
  • \เป็นวิธีที่มีประโยชน์ในการเริ่มต้นตัวเลขเป็น 0 ในประเภทเงิน eคุณสามารถแปลงค่าให้กับการลอยโดยการเพิ่ม เช่น4eหรือ\kซึ่งจะตั้งค่า k เป็นค่า 0.00 เงิน
  • rCTEดูเหมือนจะเป็นวิธีที่ดีที่สุดในการสร้างตารางตัวเลขที่น้อยกว่า 100 รายการ ยิ่งสั้นกว่าการใช้ spt_values หากคุณต้องการมากกว่า 100 ข้ามเข้าร่วมและเพิ่มพวกเขา
  • += และผู้ประกอบการผสมอื่น ๆ ถูกเพิ่มเข้ามาในปี 2008 ใช้พวกมันเพื่อบันทึกอักขระสองสามตัว
  • ตัวอักษรมักจะเป็นตัวคั่นที่ดีพอสำหรับวัตถุประสงค์นามแฝง ;คุณแทบจะไม่ต้องเป็นพื้นที่หรือ
  • ใช้การรวม ANSI SQL หากคุณต้องการ Select*from A,B where conditionสั้นกว่าselect*from A join b on condition
  • หากคุณมั่นใจได้ว่าลูปของคุณในขณะที่ทำซ้ำครั้งแรกจะเป็นการดีที่สุดที่จะเขียนซ้ำเป็นgotoลูปแบบทำในขณะที่
  • STR()เป็นฟังก์ชั่นที่สั้นที่สุดในการเปลี่ยน int เป็นสตริง หากคุณทำการแปลงมากกว่าหนึ่งครั้งหรืออาจต้องเชื่อมข้อมูลประเภทต่าง ๆ เข้าด้วยกันให้พิจารณาconcatฟังก์ชัน เช่น'hello'+str(@)สั้นกว่าconcat('hello',@)แต่hello+str(@)+str(@a)ยาวกว่าconcat('hello',@,@a)

ตัวอย่างเช่นทั้งสองนี้มีความหมายเทียบเท่ากัน

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

คุณสามารถใช้Valuesเพื่อสร้างตารางหรือแบบสอบถามย่อย นี่จะเป็นประโยชน์จริงๆถ้าคุณต้องการค่าคงที่สองสามแถว


สำหรับฉัน $ เป็นบิตชัดเจนกว่า \ เพื่อเริ่มต้นตัวเลขเป็น 0 ในประเภทเงิน YMMV
user1443098

5

การบีบอัดรหัสโดยใช้ SQL

SQL นั้นใช้คำพูดได้คะแนนสูงและมากเท่ากับที่เรารักมีSELECT FROM WHEREค่า 23 ไบต์ทุกการใช้งาน คุณสามารถบีบอัดคำเหล่านี้และคำซ้ำ ๆ หรือตัวอย่างโค้ดทั้งหมด การทำเช่นนี้จะช่วยลดต้นทุนส่วนต่างของรหัสซ้ำเป็น 1 ไบต์! *

มันทำงานอย่างไร:

  • ตัวแปรถูกประกาศและกำหนดรหัส SQL ที่บีบอัด
  • ตารางปรับเปลี่ยนตัวแปร แต่ละแถว deflates ตัวแปร
  • ตัวแปรที่ถูกแก้ไขจะถูกดำเนินการ

ปัญหา:

ค่าใช้จ่ายล่วงหน้าอยู่ใกล้กับ 100 ไบต์และแต่ละแถวในตารางการแทนที่มีค่าใช้จ่ายอีก 6 ไบต์ ตรรกะชนิดนี้จะไม่ได้ผลมากเว้นแต่คุณจะทำงานกับโค้ดจำนวนมากซึ่งคุณไม่สามารถตัดทอนหรือความท้าทายนั้นมาจากการบีบอัด

นี่คือตัวอย่าง

ความท้าทายคือการได้ทวีคูณ 10 เท่าของ 2,3 และ 5 นำไปสู่ ​​n สมมติว่านี่ ( 343 ไบต์ golfed ) เป็นทางออกที่ดีที่สุดที่ฉันจะได้รับ:

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

ตัวอย่างหลังจากรหัสถูกบีบอัด

รันนี้รหัสเดียวกันกับข้างต้นเป็น ~ 302 ไบต์แข็งแรงเล่นกอล์ฟ

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)

กลยุทธ์ที่ยอดเยี่ยมสไตล์การแทนที่หลายแบบนั้นมีประโยชน์ในสถานการณ์ทั่วไปมากขึ้นเช่นกัน
BradC

1
หลังจากการทดสอบบางอย่างผมได้พิจารณาแล้วว่าถ้ารายการของคุณของการเปลี่ยนมี7 หรือน้อยกว่ารายการที่คุณต้องการบันทึกไบต์โดยทำSELECT @=REPLACE(@,i,j)FROM(VALUES(...)x(i,j)แทนการใช้คอลัมน์เดียวกับและLEFT() SUBSTRING()หากคุณมี 8 คนขึ้นไปการหลีกเลี่ยงการเพิ่มราคาและเครื่องหมายจุลภาคเป็นการแลกเปลี่ยนที่ดี
BradC

ที่จริงแล้วสำหรับการแทนที่ 4 ครั้งหรือน้อยกว่านั้นคุณจะประหยัดไบต์ด้วยรูปแบบที่ล้าสมัยSET @=REPLACE(REPLACE(REPLACE(...
BradC

4

นี่เป็นเรื่องตลก สิ่งนี้จะแปลงค่าในคอลัมน์เป็น tuple เดียว

แก้ไข: ขอบคุณสำหรับความคิดเห็น ดูเหมือนว่าวิธีที่สั้นที่สุดในการเลื่อนโดยไม่มีแท็ก XML คือ:

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

หมายเหตุ: ถ้า XML เป็นเอาต์พุตที่ถูกต้องคุณสามารถละเว้นการเลือก outer และ parens นอกจากนี้ยังใช้column1+''งานได้กับสตริงเท่านั้น สำหรับประเภทหมายเลขจะดีที่สุดที่จะทำcolumn1+0


1
<column_name>value1</column_name><column_name>value2</column_name>...จริงๆแล้วมันจะกลับมา เพื่อที่จะได้ CSV จากคอลัมน์ที่คุณสามารถDECLARE @ VARCHAR(MAX)='';SELECT @+=column_name+',' FROM table_name;SELECT @(ขอบคุณสำหรับ @ เคล็ดลับแรกของ MichaelB) value1,value2,...ซึ่งจะกลับมา อย่างไรก็ตามจริงๆแล้วมันยาวเกิน 9 ตัวอักษร XML ของคุณ :(
Jacob

1
หมายเหตุคุณสามารถทำสิ่งนี้ให้สั้นลงได้ Ltrimไม่จำเป็นต้องเป็นเลือก (เลือก ... สำหรับเส้นทาง XML ( '')) nvarchar(max)ส่งกลับ นอกจากนี้เพื่อแก้ปัญหาคอลัมน์เพียงแค่ใช้การแสดงออกที่ไม่กลายพันธุ์ สำหรับตัวเลขที่คุณสามารถทำได้v+0สำหรับสตริงเพิ่มสตริงว่างเปล่า ฯลฯ แม้ว่าฉันจะไม่คิดว่านี่เป็นเคล็ดลับการเล่นกอล์ฟ แต่นี่เป็นเพียงความเศร้าของความเป็นจริงของวิธีการเขียนแบบสอบถามในเซิร์ฟเวอร์ sql
Michael B

3

มันเป็นไปได้ที่จะใช้บางบิตผู้ประกอบการใน T-SQL

ฉันไม่มีตัวอย่างที่เป็นรูปธรรม แต่ฉันเชื่อว่ามันเป็นความจริงที่รู้กันดีเมื่อเล่นกอล์ฟใน T-SQL


1
นี้ถูกต้องมาก แทนที่จะเขียนเงื่อนไขอย่างเช่นx=0 or y=0คุณสามารถเขียนสิ่งนั้นในฐานะที่เทียบเท่าเชิงตรรกะx|y=0ซึ่งช่วยประหยัดได้ไม่กี่ไบต์!
Michael B


3

สัญกรณ์วิทยาศาสตร์เป็นวิธีที่สั้นกว่าที่จะแสดงตัวเลขขนาดใหญ่มากและมีขนาดเล็กมากเช่นselect 1000000000= select 1E9และ=select 0.000001select 1E-6


2

Michael B พูดถึงการใช้ CTE แบบเรียกซ้ำสำหรับตารางตัวเลขแต่ไม่ได้แสดงตัวอย่าง นี่เป็นเวอร์ชั่น MS-SQL ที่เราได้ทำในเธรดอื่นนี้ :

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

โปรดทราบว่าคุณสามารถเปลี่ยนค่าเริ่มต้น ( 1 n) ช่วงเวลา ( n + 1) และค่าสิ้นสุด ( n < 99)

หากคุณต้องการมากกว่า 100 แถวคุณจะต้องเพิ่มoption (maxrecursion 0):

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

หรือเข้าร่วม rCTE กับตัวเอง:

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

แม้ว่าอันสุดท้ายนี้ไม่รับประกันว่าจะส่งคืนในลำดับตัวเลขหากไม่มี ORDER BY 1


2

ใช้การบีบอัด GZIP สำหรับสตริงที่ยาวมาก!

ดังนั้นฉันจึงรู้ว่า SQL 2016 ได้เพิ่มCOMPRESSฟังก์ชั่น (และ a)DECOMPRESSฟังก์ชั่น) ซึ่ง (ในที่สุด) นำความสามารถในการ GZIP สตริงหรือไบนารี

ปัญหาคือมันไม่ชัดเจนในทันทีว่าจะใช้ประโยชน์จากสิ่งนี้เพื่อเล่นกอล์ฟ; COMPRESSสามารถใช้สตริง แต่ส่งกลับ a VARBINARYซึ่งสั้นกว่าเป็นไบต์ (เมื่อเก็บไว้ในVARBINARYเขตข้อมูลSQL ) แต่จะยาวกว่าในตัวอักษร (hex ดิบ)

ฉันเคยเล่นมาก่อนหน้านี้ แต่ในที่สุดฉันก็สามารถรวบรวมเวอร์ชั่นที่ใช้งานได้ตามคำตอบเก่า ๆ ของ SOคำตอบนี้เก่าในดังนั้นโพสต์นั้นไม่ได้ใช้ฟังก์ชัน GZIP ใหม่ แต่แปลงเป็นVARBINARYสตริงที่เข้ารหัส Base-64 เราแค่ต้องใส่ฟังก์ชั่นใหม่เข้าไปในสถานที่ที่เหมาะสม

นี่คือรหัสที่คุณสามารถใช้ในการแปลงสตริงที่ยาวมากของคุณเป็นสตริงที่บีบอัดที่เข้ารหัส 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))

เอาท์พุทและใช้มันในรหัสของคุณในสถานที่ของสตริงยาวเดิมพร้อมกับ:

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

ดังนั้นแทนที่จะเป็นรหัสเดิมของคุณ ( 1471 ไบต์ )

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

คุณมี ( 1034 ไบต์ ):

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

ดูคำตอบนี้ซึ่งช่วยฉันได้เกือบ 200 ไบต์

ฉันยังไม่ได้ทำคณิตศาสตร์ แต่ชัดเจนเนื่องจากค่าใช้จ่ายนี้จะมีผลเฉพาะกับสายที่ยาวมากเท่านั้น อาจมีสถานที่อื่นที่ไม่สามารถใช้งานได้ ฉันได้ค้นพบแล้วคุณต้องSELECTคุณไม่สามารถPRINTมิฉะนั้นคุณจะได้รับ:

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

แก้ไข : รุ่นย่อของรหัสการขยาย, ความอนุเคราะห์ของ @digscoop :

บันทึก 10 ไบต์ด้วยการเปลี่ยนด้านนอกCASTเป็นการแปลงโดยนัยโดยใช้CONCAT:

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

นอกจากนี้คุณยังสามารถประกาศตัวแปรประเภทXMLแทนVARCHAR(MAX)และบันทึกในCAST:

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

ตัวมันเองจะยาวกว่านี้เล็กน้อยแต่ถ้าคุณต้องการตัวแปรในเหตุผลอื่นก็อาจช่วยได้


ดีฉันไม่รู้จัก SQL แต่นี่ก็ดูเท่ห์
MilkyWay90

1

ความคิดเล็กน้อยเกี่ยวกับการสร้างและใช้ตารางสำหรับความท้าทาย:

1. อินพุต SQL สามารถดำเนินการผ่านตารางที่มีอยู่แล้ว

รหัสกอล์ฟวิธีการอินพุต / เอาท์พุต :

SQL อาจรับอินพุตจากตารางที่ระบุชื่อ

การสร้างและเติมข้อมูลในตารางนี้ด้วยค่าอินพุตจะไม่นับรวมกับจำนวนไบต์ทั้งหมดของคุณคุณสามารถสันนิษฐานได้ว่ามันมีอยู่แล้ว

ซึ่งหมายความว่าการคำนวณของคุณสามารถแสดงผลผ่าน SELECT อย่างง่ายจากตารางอินพุต:

SELECT 2*SQRT(a)FROM t

2. ถ้าเป็นไปได้อย่าสร้างตารางเลย

แทน (69 ไบต์):

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

ทำเพียง (43 ไบต์):

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

3. ถ้าเป็นไปได้ให้สร้างตารางด้วย SELECT INTO

แทน (39 ไบต์):

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

ทำสิ่งนี้ (17 ไบต์):

SELECT 2 p INTO t

4: พิจารณาการรวมหลายคอลัมน์เข้าด้วยกัน

นี่คือสองรูปแบบที่คืนค่าผลลัพธ์เดียวกัน:

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)

หลังจากการทดสอบบางอย่างรุ่นบนสุด (หลายคอลัมน์) ดูเหมือนจะสั้นลงด้วย7 หรือน้อยกว่าแถวรุ่นด้านล่าง (เนื่องจากซ้ายและ SUBSTRING) จะสั้นกว่าด้วย8 แถวขึ้นไป ระยะทางของคุณอาจแตกต่างกันไปขึ้นอยู่กับข้อมูลที่แน่นอนของคุณ

5: ใช้ REPLACE และ EXEC สำหรับลำดับข้อความที่ยาวมาก

ในหลอดเลือดดำของคำตอบที่ดีเยี่ยมอย่างสบายๆ ถ้าคุณมีค่า15 ค่าขึ้นไปใช้REPLACEสัญลักษณ์เพื่อกำจัดสิ่งที่ซ้ำกัน'),('ตัวคั่นระหว่างองค์ประกอบ:

114 ตัวอักษร:

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

112 ตัวอักษร:

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

หากคุณแล้วใช้ SQL แบบไดนามิกด้วยเหตุผลอื่น (หรือมีการแทนที่หลายรายการ) แสดงว่าเกณฑ์ที่นี่มีค่าต่ำกว่ามาก

6: ใช้ SELECT กับคอลัมน์ที่มีชื่อแทนที่จะเป็นกลุ่มของตัวแปร

แรงบันดาลใจจากคำตอบที่ยอดเยี่ยมของ jmlt ที่นี่ใช้สายอักขระผ่านทาง 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

ผลตอบแทน

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

(สำหรับ MS SQL ผมเปลี่ยน\tไปผลตอบแทนในสายการผลิตและการเปลี่ยนแปลงCONCAT()เพื่อ+ที่จะบันทึก bytes)


1

แท็กรหัสของคุณสำหรับการเน้นไวยากรณ์ T-SQL

แทนที่จะเป็นเพียงแค่:

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

รวมแท็กภาษาดังนี้:

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

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

และผลลัพธ์จะเป็น:

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

1

ใช้ประโยชน์จากคุณสมบัติ / ฟังก์ชั่นใหม่ใน MS SQL 2016 และ SQL 2017

หากคุณไม่มีสำเนาภายในเครื่องคุณสามารถเล่นออนไลน์ด้วยStackExchange Data Explorer (SQL 2016) หรือกับdbfiddle.uk (SQL 2016 หรือ SQL "vNext")

STRING_SPLIT ( SQL 2016 ขึ้นไป )

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

หากคุณต้องการนามแฝงของตารางหรืออ้างถึงชื่อคอลัมน์:

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

TRIM ( SQL 2017 หรือใหม่กว่า )

สั้นกว่าและแน่นอนสั้นกว่าRTRIM()LTRIM(RTRIM())

นอกจากนี้ยังมีตัวเลือกในการลบอักขระอื่นหรือชุดอักขระจากจุดเริ่มต้นหรือจุดสิ้นสุด:

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

ผลตอบแทน L Server 2

แปล ( SQL 2017 หรือใหม่กว่า )

TRANSLATEอนุญาตให้คุณแทนที่อักขระหลายตัวในขั้นตอนเดียวแทนที่จะเป็นREPLACEข้อความสั่งซ้อนกัน แต่อย่าเฉลิมฉลองมากเกินไปเพียงแทนที่อักขระเดี่ยวแต่ละตัวด้วยอักขระเดี่ยวที่แตกต่างกัน

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

อักขระแต่ละตัวในสตริงที่สองจะถูกแทนที่ด้วยอักขระที่เกี่ยวข้องในสตริงที่สาม

ดูเหมือนว่าเราสามารถกำจัดตัวละครจำนวนมากด้วยสิ่งที่ชอบ REPLACE(TRANSLATE('source string','ABCD','XXXX'),'X','')


บางคนที่น่าสนใจเช่นกันเช่นเดียวกับที่CONCAT_WSและSTRING_AGGอาจมีค่าดูเช่นกัน


1

วัวศักดิ์สิทธิ์ฉันได้ค้นพบความมหัศจรรย์ของPARSENAME( SQL 2012 หรือสูงกว่า )

ฟังก์ชั่นถูกสร้างขึ้นเพื่อแยกส่วนของชื่อวัตถุที่ชอบservername.dbname.dbo.tablenameแต่มันทำงานได้สำหรับค่าที่คั่นด้วยจุดใด ๆ แค่จำไว้ว่ามันนับจากทางขวาไม่ใช่ทางซ้าย:

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 ค่าจะส่งคืนNULLส่วนที่เหลือ (แต่ยังนับจากขวาไปซ้าย ):

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

นี่คือสิ่งที่เวทมนตร์เข้ามา: รวมเข้ากับSTRING_SPLIT(2016 หรือสูงกว่า) เพื่อสร้างตารางหลายคอลัมน์ในหน่วยความจำ !!

เก่าและถูกจับ:

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

ใหม่ร้อนแรง:

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

เห็นได้ชัดว่าการประหยัดที่แท้จริงของคุณขึ้นอยู่กับขนาดและเนื้อหาของตารางและวิธีการใช้งานของคุณ

โปรดทราบว่าถ้าเขตข้อมูลของคุณมีความกว้างคงที่คุณควรใช้LEFTและRIGHTแยกเขตข้อมูลเหล่านั้นแทนPARSENAME(ไม่ใช่เพียงเพราะชื่อฟังก์ชันสั้นกว่า แต่ยังเป็นเพราะคุณสามารถกำจัดตัวแยกทั้งหมดได้)


ฉันไม่แน่ใจว่าเมื่อ PARSENAME ออกมา แต่มีบทความที่อธิบายไว้ตั้งแต่ปี 2003
t-clausen.dk

1

เคล็ดลับที่ไม่เกี่ยวข้องอีกสองสามข้อที่ฉันเห็นและต้องการรักษา:

  1. ใช้GO #เพื่อทำซ้ำบล็อกตามจำนวนครั้งที่ระบุ

เห็นเคล็ดลับฉลาดนี้ในคำตอบที่ดีเยี่ยมของพอล

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

แน่นอนว่าสิ่งนี้จะรีเซ็ตตัวแปรตัวนับใด ๆ ในบล็อกดังนั้นคุณต้องชั่งน้ำหนักกับWHILEลูปหรือx: ... GOTO xลูป

  1. SELECT TOP ... FROM systypes

จากคำถามเดียวกันกับของ Paul ด้านบนAnuj Tripathi ใช้เคล็ดลับต่อไปนี้ :

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

หรือตามที่แนะนำโดย pinkfloydx33 ในความคิดเห็น:

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

หมายเหตุนี้ไม่ได้พึ่งพาใด ๆ ที่เกิดขึ้นจริงเนื้อหาของsystypesเพียงว่ามุมมองของระบบที่มีอยู่ (ซึ่งมันไม่ได้ในทุกฐานข้อมูล MS SQL) และมีอย่างน้อย 10 แถว (มันก็ดูจะมี 34 รุ่นล่าสุดของ SQL ) ฉันไม่พบมุมมองระบบใด ๆ ที่มีชื่อที่สั้นกว่า (ที่ไม่ต้องใช้sys.คำนำหน้า) ดังนั้นนี่อาจเหมาะ


1

ดู คำถามนี้ใน dba.stackexchangeสำหรับแนวคิดที่น่าสนใจสำหรับการเพิ่มคอลัมน์ตัวเลขในผลลัพธ์ STRING_SPLIT

รับสายเหมือน'one,two,three,four,five'เราต้องการได้รับสิ่งที่ชอบ:

value   n
------ ---
one     1
two     2
three   3
four    4
five    5
  1. คำตอบของ Joe Obbish ใช้ROW_NUMBER()และเรียงโดยNULLหรือค่าคงที่:

    SELECT value, ROW_NUMBER() OVER(ORDER BY (SELECT 1))n
    FROM STRING_SPLIT('one,two,three,four,five',',')
    
  2. คำตอบของ Paul White ใช้SEQUENCE :

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

ลำดับเป็นวัตถุถาวรที่น่าสนใจ คุณสามารถกำหนดชนิดข้อมูลค่า min และ max ช่วงเวลาและไม่ว่าจะล้อมรอบไปที่จุดเริ่มต้น:

    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 ของคุณสามารถใช้ฟังก์ชั่น (ซึ่งไม่ได้เช่นเดียวกับคุณสมบัติร่วมกับ INSERT:IDENTITY() IDENTITY

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

โปรดทราบว่าพารามิเตอร์สองตัวสุดท้ายIDENTITY(INT,1,1)เป็นตัวเลือกและจะใช้ค่าเริ่มต้นเป็น 1 หากไม่รวม


ปัญหาคือ STRING_SPLIT ไม่รับประกันการคืนสินค้า คุณอาจคิดว่ามันจะส่งกลับ rowset ตามลำดับของโทเค็นในสตริงเดิมเสมอ แน่นอนมันอาจทำเช่นนั้น! อย่างไรก็ตามไม่มีการรับประกันในเอกสาร ไม่เป็นไรถ้าคุณไม่สนใจเกี่ยวกับการสั่งซื้อ แต่ถ้าคุณทำ (เช่นการแยกแถวในรูปแบบ CSV) แสดงว่ามีปัญหา
user1443098

1
@ user1443098 ในที่สุดฉันเห็นด้วยกับคุณในบริบทของการแนะนำรหัสเพื่อจุดประสงค์ทางธุรกิจเช่นที่เราอาจเห็นใน dba.SE แต่สำหรับความท้าทายใน PPCG มาตรฐานของฉันแตกต่างกันเล็กน้อย หากในการทดสอบโค้ดของฉันคืนแถวตามลำดับที่ฉันต้องการฉันจะบันทึกไบต์ที่ฉันสามารถทำได้ คล้ายกับวิธีที่ฉันจะออกไปORDER BYถ้าฉันสามารถไปกับมัน (ดูคำตอบของฉันToasty, Burnt, Bruleeเป็นต้น)
BradC

1

เพิ่งค้นพบว่าคุณสามารถใช้ตัวเลขสำหรับตัวเดียวREPLACEเพื่อกำจัดคำพูด :

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

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

นี้เป็นเพราะ REPLACEการแปลงเป็นสตริงโดยนัย

ทั้งสองผลิตผลลัพธ์เดียวกัน:

Baby Shark doo doo doo doo doo doo

0

_ และ # เป็นชื่อแทนที่ถูกต้อง ฉันใช้พวกเขากับ CROSS APPLY เพื่อทำให้คอลัมน์ที่ส่งคืนนั้นเป็นส่วนหนึ่งของส่วนคำสั่ง FROM เช่น

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

ฉันชอบสิ่งนี้เมื่อวัตถุประสงค์เดียวของ CROSS APPLY คือการคำนวณการแสดงออก

สำหรับเรื่องนั้นการใช้ APPLY สำหรับการคำนวณนิพจน์ย่อยเป็นวิธีที่เรียบร้อยในการทำให้โค้ดของคุณแห้ง (และสั้นกว่า) จากสิ่งที่ฉันเห็นในแผนการดำเนินการไม่มีค่าใช้จ่ายเพิ่มเติมสำหรับวิธีการนี้ คอมไพเลอร์คิดว่าคุณแค่คำนวณอะไรบางอย่างแล้วปฏิบัติเหมือนมันเป็นนิพจน์อื่น ๆ


ฉันพบว่าการใช้กากบาทเป็นเวลานานมันยากที่จะหาสถานการณ์ที่มีประโยชน์โดยใช้การใช้กากบาทโดยไม่ต้องหาวิธีที่สั้นกว่าอีก
t-clausen.dk

ตกลง - ย่อตัวอย่างที่ให้ไว้ด้านบน!
user1443098

เลือกหมายเลข 10 อันดับแรกหมายเลข * 2 n2 จาก master.dbo.spt_values ​​v
t-clausen.dk

ฉันหมายถึงการเข้าร่วม โดยวิธีการเมื่อคุณสร้างแบบสอบถาม XML, CROSS ใช้เป็นวิธีเดียวที่จะทำเพราะอาจจะไม่มีคอลัมน์ในแบบสอบถามย่อยจะเข้าร่วม
user1443098

Subselect สั้นกว่าการใช้ไขว้: SELECT top 10 * จาก (เลือกหมายเลข n, หมายเลข * 2n2 จากต้นแบบ ..spt_values) x
t-clausen.dk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.