SQL Server รองรับ GREATEST และ LEAST หรือไม่หากไม่ใช่วิธีแก้ไขปัญหาทั่วไป


20

การตรวจสอบคำถามนี้ดูเหมือนว่าเป็นงานที่ไม่ควรทำ พวกเขากำลังพยายามขยายช่วงด้วยวันที่ ในฐานข้อมูลอื่นคุณจะใช้greatestและleast..

least(extendDate,min), greatest(extendDate,max)

เมื่อฉันพยายามใช้สิ่งเหล่านี้ฉันก็จะได้

'least' is not a recognized built-in function name.
'greatest' is not a recognized built-in function name.

ที่จะครอบคลุมนามสกุลในทิศทางใดทิศทางหนึ่ง

สำหรับวัตถุประสงค์ของคำถามคุณยังคงต้องทำการเปลี่ยนช่วงพิเศษ

ฉันแค่สงสัยว่าผู้ใช้ SQL Server ใช้รูปแบบแบบสอบถามเพื่อเลียนแบบleastและการgreatestทำงานได้อย่างไร

คุณคลายเงื่อนไขลงในCASEข้อความสั่งหรือมีส่วนเสริม, โปรแกรมเสริมของบุคคลภายนอกหรือใบอนุญาตจาก Microsoft ที่เปิดใช้งานฟังก์ชันนี้หรือไม่?


คำตอบ:


33

วิธีการทั่วไปอย่างหนึ่งคือการใช้ส่วนVALUESคำสั่งและCROSS APPLYคอลัมน์ทั้งสองนั้นใช้นามแฝงเป็นคอลัมน์เดียวจากนั้นรับMINและMAXของแต่ละคอลัมน์

SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM   dbo.Users AS u
CROSS APPLY ( VALUES ( u.CreationDate ), ( u.LastAccessDate )) AS x ( CombinedDate );

มีวิธีอื่นในการเขียนเช่นการใช้ UNION ALL

SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM   dbo.Users AS u
CROSS APPLY ( SELECT u.CreationDate UNION ALL SELECT u.LastAccessDate ) AS x(CombinedDate);

อย่างไรก็ตามแผนคิวรีที่เป็นผลลัพธ์ดูเหมือนจะเหมือนกัน


14

นอกจากนี้คุณยังสามารถใส่ค่าแบบอินไลน์ในแบบสอบถามย่อย แบบนี้:

select (select max(i) from (values (1), (2), (5), (1), (6)) AS T(i)) greatest,
       (select min(i) from (values (1), (2), (5), (1), (6)) AS T(i)) least

3

นี่จะเป็นการเริ่มต้นที่ดี -

CASE WHEN A > B THEN A ELSE B END

มันเป็นข้อเสนอแนะที่ดี แต่มันถูกกล่าวถึงในคำถามด้วย "การคลี่คลายเงื่อนไขในคำสั่ง CASE"
Evan Carroll

3

อย่างน้อยเทียบเท่า:

IIF(@a < @b, @a, @b)

ยิ่งใหญ่เทียบเท่า:

IIF(@a > @b, @a, @b)

3
คุณจะทำเช่นนั้นสำหรับค่าสามค่าขึ้นไปได้least(5,6,7,8,9)อย่างไร
a_horse_with_no_name

@a_horse_with_no_name ใช้ IIF ที่ซ้อนกัน
Elnur

วิธีการนี้จะท้าทายในการอ่านและตรวจสอบอย่างรวดเร็ว ... มันมีค่าในแง่ของประสิทธิภาพอย่างไร
Dodecaphone

0

ฉันสร้างฟังก์ชั่นที่ผู้ใช้กำหนดเช่น

create function dbo.udf_LeastInt(@a int, @b int)
returns int
with schemabinding
as
begin
  return case when @a <= @b then @a 
              when @b < @a  then @b
              else null
         end
end

แม้ว่ามันอาจใช้งานได้ในกรณีง่าย ๆ แต่ก็มีปัญหาหลายประการเกี่ยวกับวิธีการนี้:

  • น่ารำคาญคุณต้องแยกฟังก์ชั่นสำหรับแต่ละประเภทข้อมูล
  • มันจัดการเพียง 2 พารามิเตอร์ดังนั้นหนึ่งอาจต้องการฟังก์ชั่นเพิ่มเติมเพื่อจัดการกับพารามิเตอร์จำนวนมากหรือใช้การโทรซ้อนกันของฟังก์ชั่นเดียวกัน
  • มันจะดีกว่า (มีประสิทธิภาพมากขึ้น) ในฐานะ TVF แบบอินไลน์แทนที่จะเป็นฟังก์ชันสเกลาร์ ที่เกี่ยวข้องกับการใช้ฟังก์ชั่นสเกลาร์ที่เป็นหัวใจ มีหลายบล็อกเกี่ยวกับเรื่องนี้มีความเห็นเช่นเกลาฟังก์ชั่นที่ผู้ใช้กำหนด (โดยจอห์น Kehayias
  • หากหนึ่งในข้อโต้แย้งนั้นเป็นโมฆะมันจะส่งกลับค่าว่าง สิ่งนี้ตรงกับสิ่งที่leastผู้ปฏิบัติงานทำใน Oracle และ MySQL แต่แตกต่างจาก Postgres แต่ armouring นี้กับ null ทำให้มันมากขึ้นอย่างละเอียด (ถ้าคุณรู้ว่าพวกเขาจะไม่เป็นโมฆะธรรมดาcase when @a <= @b then @a else @b endจะทำงาน)

โดยรวมแล้วอาจเป็นการดีกว่าถ้าจะเขียนcaseคำแถลงนี้ไว้นาน ๆ หากประสิทธิภาพมีความสำคัญ ฉันยังใช้วิธีการสร้างcaseคำสั่งซ้อนกันในฝั่งไคลเอ็นต์เมื่อมีหลายค่าที่จะเปรียบเทียบ


0

ฉันต้องการเพิ่มความคิดเห็นในคำตอบ @ ed-avis แต่ไม่สามารถทำได้เนื่องจากขาดชื่อเสียงดังนั้นการโพสต์สิ่งนี้เป็นส่วนขยายของคำตอบของเขา

ฉันได้ตัดข้อเสียของ "น่ารำคาญคุณต้องแยกฟังก์ชั่นสำหรับแต่ละประเภทข้อมูล" ใช้sql_variant

นี่คือการดำเนินการของฉัน:

CREATE OR ALTER FUNCTION my_least(@a SQL_VARIANT, @b SQL_VARIANT)
returns SQL_VARIANT
with schemabinding
as
begin
  return case when @a <= @b then @a 
              when @b < @a  then @b
              WHEN @a IS NULL THEN @b
              WHEN @b IS NULL THEN @a
              else null
         end
END;

ฟังก์ชั่นนี้ยังจัดการกับNULLเช่นรุ่น postgresql

ฟังก์ชั่นนี้อาจจะเพิ่มฐานข้อมูลเพื่อความสะดวกสบาย แต่ก็10 ครั้งช้าIIFกว่าใช้สร้างขึ้นใน การทดสอบของฉันแสดงให้เห็นว่าการทำงานดังกล่าวกับชนิดที่แน่นอน ( datetime ) ดำเนินการเช่นเดียวกับsql_variantรุ่น

ป.ล. ฉันใช้การทดสอบบางอย่างกับชุดข้อมูลที่มีค่า 350k และดูเหมือนว่าประสิทธิภาพจะเหมือนกันsql_variantเร็วขึ้นเล็กน้อย แต่ฉันเชื่อว่ามันเป็นแค่เรื่องกระตุก

แต่เวอร์ชัน IIF ก็เร็วขึ้น10เท่า !!!

ฉันไม่ได้ทำการทดสอบแบบอินไลน์CASE WHENแต่โดยทั่วไปแล้วสำหรับ t-sql IIF เหมือนกับ caseและ iif get's ถูกแปลงโดย optimizer ไปเป็น expression ของ case

ข้อเท็จจริงที่ว่า IIF ถูกแปลเป็น CASE ก็มีผลกระทบในด้านอื่น ๆ ของพฤติกรรมของฟังก์ชันนี้

สรุป:ใช้IIFเร็วกว่าหากประสิทธิภาพมีความสำคัญ แต่สำหรับการสร้างต้นแบบหรือถ้าต้องการความชัดเจนของรหัสมากขึ้นและไม่ต้องมีการคำนวณขนาดใหญ่ให้ใช้ฟังก์ชันนี้ได้


LEAST () และ GREATEST () เมื่อมีอยู่ในภาษา SQL อนุญาตการเปรียบเทียบภายในแถวระหว่างคอลัมน์ n; ฉันเลือก OP เพื่อให้เป็นโซลูชันที่จะให้ผลลัพธ์ที่เท่าเทียมกัน คำตอบที่นี่ (พร้อมด้วยคนอื่น ๆ ) สนับสนุนเพียง 2
Dodecaphone
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.