รับค่าต่ำสุดสองค่าใน SQL


180

ฉันมีสองตัวแปรหนึ่งที่เรียกว่าPaidThisMonthและอื่น ๆ OwedPastเรียกว่า ทั้งคู่เป็นผลลัพธ์ของแบบสอบถามย่อยบางรายการใน SQL ฉันจะเลือกขนาดเล็กกว่าสองค่าและคืนค่าเป็นชื่อได้PaidForPastอย่างไร

MINฟังก์ชั่นการทำงานในคอลัมน์ไม่ตัวแปร


1
หากคุณใช้ Postgres หรือ MySQL ให้ข้ามไปที่คำตอบของ @ Gil_Margolin
Noumenon

คำตอบ:


127

ใช้กรณี:

   Select Case When @PaidThisMonth < @OwedPast 
               Then @PaidThisMonth Else @OwedPast End PaidForPast

ในฐานะที่เป็นตาราง Inline มูลค่า UDF

CREATE FUNCTION Minimum
(@Param1 Integer, @Param2 Integer)
Returns Table As
Return(Select Case When @Param1 < @Param2 
                   Then @Param1 Else @Param2 End MinValue)

การใช้งาน:

Select MinValue as PaidforPast 
From dbo.Minimum(@PaidThisMonth, @OwedPast)

เพิ่ม: สิ่งนี้น่าจะดีที่สุดเมื่อพูดถึงค่าที่เป็นไปได้เพียงสองค่าหากมีมากกว่าสองค่าให้พิจารณาคำตอบของ Craigโดยใช้ส่วนคำสั่ง Values


ไวยากรณ์ที่เข้าใจได้ดีกว่า: return (เลือก minValue = case เมื่อ @@ param1 <@@ param2 จากนั้น @@ param1 else @@ param2 end) ตกลงนี้อาจไม่ได้มาตรฐานฉันไม่รู้ แต่มันเป็นที่เข้าใจมากขึ้นและควรทำให้เป็นมาตรฐาน
Softlion

1
อีกเหตุผลหนึ่งที่ต้องการคำตอบของ @ Craig ด้านล่างนี้เป็นเพราะการจัดการที่ไม่มีค่า หากค่าที่จะเปรียบเทียบนั้นเป็นโมฆะและหนึ่งในค่าที่จะเปรียบเทียบนั้นเป็นโมฆะสวิตช์ตัวพิมพ์ที่แสดงอาจส่งคืนค่าว่างหรือค่าขึ้นอยู่กับลำดับของการทดสอบ WHEN (ยกเว้นว่าคุณเพิ่มการใช้ ISNULL) วิธีของ Craig จะชอบการเลือกค่าที่ไม่เป็นโมฆะซึ่งดูเหมือนว่าถูกต้องมากกว่าสำหรับฉันอย่างน้อยในกรณีใช้งานปัจจุบันของฉันในการเปรียบเทียบวันที่ไม่มีค่า
Nij

148

SQL Server 2012 และ 2014 รองรับฟังก์ชั่น IIF (ต่อ, จริง, เท็จ) ดังนั้นสำหรับการเลือกน้อยที่สุดคุณสามารถใช้งานได้เช่น

SELECT IIF(first>second, second, first) the_minimal FROM table

ในขณะที่IIFเป็นเพียงชวเลขสำหรับการเขียนCASE...WHEN...ELSEมันง่ายกว่าในการเขียน


8
IIFCASE...WHEN...ELSEเป็นเพียงน้ำตาลประโยคสำหรับ
Salman

55
อาจเป็นไปได้ แต่เขียนง่ายกว่า
Mert Gülsoy

1
@ MertGülsoyและง่ายต่อการอ่านซึ่งควรจะอยู่ด้านบนของรายการลำดับความสำคัญของทุกคนหลังจากความถูกต้อง
แดเนียล

119

โซลูชันที่ใช้ CASE, IIF และ UDF นั้นเพียงพอ แต่ไม่สามารถทำได้เมื่อขยายปัญหาไปยังเคสทั่วไปโดยใช้มากกว่า 2 ค่าเปรียบเทียบ โซลูชันทั่วไปใน SQL Server 2008+ ใช้แอปพลิเคชันที่แปลกประหลาดของ VALUES clause:

SELECT
PaidForPast=(SELECT MIN(x) FROM (VALUES (PaidThisMonth),(OwedPast)) AS value(x))

เครดิตเนื่องจากเว็บไซต์นี้: http://sqlblog.com/blogs/jamie_thomson/archive/2012/01/20/use-values-clause-to-get-the-maximum-value-from-some-columns-sql- เซิร์ฟเวอร์เสื้อ sql.aspx


12
นี่คือคำตอบที่ดีที่สุด
FindOutIslamNow

ถ้าคุณต้องการ min ไม่ใช่ศูนย์:MIN(x*(case x when 0 then null else 1 end))
mpag

ยกเว้น MartinC ให้คำตอบเดียวกันเมื่อสี่ปีก่อนและแสดงให้เห็นจริง ๆ แล้วมันมีค่ามากกว่าสองค่า ...
Auspex

4
Auspex คำตอบของ MartinC นั้นไม่เกี่ยวข้องกัน คำตอบนี้ไม่ได้ใช้สหภาพ
Craig

30

ฉันเพิ่งมีสถานการณ์ที่ฉันต้องค้นหาจำนวนสูงสุด 4 ตัวเลือกในการอัปเดต ด้วยวิธีนี้คุณสามารถมีได้มากเท่าที่คุณต้องการ!

นอกจากนี้คุณยังสามารถแทนที่ตัวเลขด้วยการเลือกเพิ่มเติม

select max(x)
 from (
 select 1 as 'x' union
 select 4 as 'x' union
 select 3 as 'x' union
 select 2 as 'x' 
 ) a

การใช้งานที่ซับซ้อนมากขึ้น

 @answer = select Max(x)
           from (
                select @NumberA as 'x' union
                select @NumberB as 'x' union
                select @NumberC as 'x' union
                select (
                       Select Max(score) from TopScores
                       ) as 'x' 
     ) a

ฉันแน่ใจว่า UDF มีประสิทธิภาพที่ดีขึ้น


ฉันชอบสิ่งนี้มากที่สุดเนื่องจากเป็น SQL พื้นฐาน นอกจากนี้ UDF ไม่จำเป็นต้องเร็วขึ้น สำหรับร้านค้าคอลัมน์ส่วนใหญ่แต่ละแอ็ตทริบิวต์ (ฉันสมมติว่าคุณกำลังจะกรองแอททริบิวต์ด้วย) สามารถคำนวณแบบขนานและเพียงชุดที่มีคุณสมบัติเหมาะสมถูกรวมเข้าด้วยกัน ดังนั้นสหภาพแรงงานจึงไม่ช้าอย่างแน่นอน
Bouncner

เรียบง่ายและยอดเยี่ยม
ashleedawg

22

สำหรับ MySQL หรือ PostgreSQL 9.3+ วิธีที่ดีกว่าคือการใช้LEASTและGREATESTฟังก์ชั่น

SELECT GREATEST(A.date0, B.date0) AS date0, 
       LEAST(A.date1, B.date1, B.date2) AS date1
FROM A, B
WHERE B.x = A.x

ด้วย:

  • GREATEST(value [, ...]): ส่งคืนอาร์กิวเมนต์ที่ใหญ่ที่สุด (มูลค่าสูงสุด) จากค่าที่มีให้
  • LEAST(value [, ...])ส่งคืนอาร์กิวเมนต์ที่เล็กที่สุด (ค่าต่ำสุด) จากค่าที่มีให้

ลิงค์เอกสาร:


นอกจากนี้ยังใช้งานได้ใน PostgreSQL (และเป็นสิ่งที่ฉันกำลังมองหา :) ดู: postgresql.org/docs/9.5/static/functions-conditional.html
Albert Vaca Cintora

1
นี่คือคำตอบที่ดีที่สุด
Roberto Rodriguez

2
@RobertoRodriguez มันจะดีที่สุดหากคำถามมี MySQL หรือ PostgreSQL ติดแท็กเป็นส่วนหนึ่งของคำถาม คำถามนี้เกี่ยวกับ tsql โดยเฉพาะดังนั้นคำตอบนี้ไม่ได้ช่วยอะไรเลย
Jmaurier

นี่ไม่ใช่คำตอบสำหรับ MSSQL
Mujah Maskey

13

นี่คือเคล็ดลับหากคุณต้องการคำนวณค่าสูงสุด (ฟิลด์, 0):

SELECT (ABS(field) + field)/2 FROM Table

กลับ 0 ถ้าเป็นลบอื่นกลับมาfieldfield


3
ดังนั้นในการคำนวณขั้นต่ำ (@a, @b) คุณสามารถใช้:SELECT @a - ( ABS(@a-@b) + (@a-@b) ) / 2
scottyc

1
และอย่าลืมพิมพ์ overflow;)
pkuderov

นี่คือการบันทึกจากจุดยืนความแม่นยำจุดลอยตัวหรือไม่? แน่ใจหรือไม่ว่าผลลัพธ์จะไม่ใกล้เคียงกับศูนย์ แต่เป็นลบ
zuraff

6

ใช้คำสั่ง CASE

ตัวอย่าง B ในหน้านี้ควรอยู่ใกล้กับสิ่งที่คุณพยายามทำ:
http://msdn.microsoft.com/en-us/library/ms181765.aspx

นี่คือรหัสจากหน้า:

USE AdventureWorks;
GO
SELECT   ProductNumber, Name, 'Price Range' = 
      CASE 
         WHEN ListPrice =  0 THEN 'Mfg item - not for resale'
         WHEN ListPrice < 50 THEN 'Under $50'
         WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'
         WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'
         ELSE 'Over $1000'
      END
FROM Production.Product
ORDER BY ProductNumber ;
GO

2

ใช้ตาราง temp เพื่อแทรกช่วงของค่าจากนั้นเลือก min / max ของตาราง temp จากภายในกระบวนงานที่เก็บไว้หรือ UDF นี่คือโครงสร้างพื้นฐานดังนั้นโปรดแก้ไขได้ตามต้องการ

ตัวอย่างเช่น:

CREATE PROCEDURE GetMinSpeed() AS
BEGIN

    CREATE TABLE #speed (Driver NVARCHAR(10), SPEED INT);
    '
    ' Insert any number of data you need to sort and pull from
    '
    INSERT INTO #speed (N'Petty', 165)
    INSERT INTO #speed (N'Earnhardt', 172)
    INSERT INTO #speed (N'Patrick', 174)

    SELECT MIN(SPEED) FROM #speed

    DROP TABLE #speed

END

2

สามารถใช้งานได้ถึง 5 วันและจัดการกับค่า Null ไม่สามารถทำให้มันเป็นฟังก์ชัน Inline ได้

CREATE FUNCTION dbo.MinDate(@Date1 datetime = Null,
                            @Date2 datetime = Null,
                            @Date3 datetime = Null,
                            @Date4 datetime = Null,
                            @Date5 datetime = Null)
RETURNS Datetime AS
BEGIN
--USAGE select dbo.MinDate('20120405',null,null,'20110305',null)
DECLARE @Output datetime;

WITH Datelist_CTE(DT)
AS (
        SELECT @Date1 AS DT WHERE @Date1 is not NULL UNION
        SELECT @Date2 AS DT WHERE @Date2 is not NULL UNION
        SELECT @Date3 AS DT WHERE @Date3 is not NULL UNION
        SELECT @Date4 AS DT WHERE @Date4 is not NULL UNION
        SELECT @Date5 AS DT WHERE @Date5 is not NULL
   )
Select @Output=Min(DT) FROM Datelist_CTE

RETURN @Output
END

เพิ่งรู้ว่าคุณไม่ต้องการ WHERE Clauses เนื่องจาก MIN จะลบ Nulls ต่อไป
Lawrence

2

สร้างด้วยตรรกะ / รหัสที่ยอดเยี่ยมจาก mathematix และ scottyc ฉันส่ง:

DECLARE @a INT, @b INT, @c INT = 0

WHILE @c < 100
    BEGIN
        SET @c += 1
        SET @a = ROUND(RAND()*100,0)-50
        SET @b = ROUND(RAND()*100,0)-50
        SELECT @a AS a, @b AS b,
            @a - ( ABS(@a-@b) + (@a-@b) ) / 2 AS MINab,
            @a + ( ABS(@b-@a) + (@b-@a) ) / 2 AS MAXab,
            CASE WHEN (@a <= @b AND @a = @a - ( ABS(@a-@b) + (@a-@b) ) / 2)
            OR (@a >= @b AND @a = @a + ( ABS(@b-@a) + (@b-@a) ) / 2)
            THEN 'Success' ELSE 'Failure' END AS Status
    END

แม้ว่าการกระโดดจากฟังก์ชั่น MIN ของสก็อตตี้ไปยังฟังก์ชั่น MAX ควรจะชัดเจนสำหรับฉัน แต่มันก็ไม่ได้ดังนั้นฉันจึงแก้ไขและรวมไว้ที่นี่: SELECT @ a + (ABS (@ b- @ a) + ( @ b- @ a)) / 2 ตัวเลขที่สร้างแบบสุ่มในขณะที่ไม่ใช่ข้อพิสูจน์อย่างน้อยควรโน้มน้าวให้ผู้สงสัยว่าสูตรทั้งสองนั้นถูกต้อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.