Lấy tối thiểu hai giá trị trong SQL


180

Tôi có hai biến, một biến được gọi PaidThisMonthvà biến còn lại được gọi OwedPast. Cả hai đều là kết quả của một số truy vấn con trong SQL. Làm thế nào tôi có thể chọn nhỏ hơn trong hai và trả lại nó như một giá trị có tiêu đề PaidForPast?

Các MINchức năng hoạt động trên các cột, không biến.


1
Nếu bạn đang sử dụng Postgres hoặc MySQL, hãy bỏ qua câu trả lời của @ Gil_Margolin.
Noumenon

Câu trả lời:


127

Ca sử dụng:

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

Như bảng nội tuyến có giá trị UDF

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

Sử dụng:

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

ĐỊA CHỈ: Điều này có lẽ là tốt nhất khi chỉ giải quyết hai giá trị có thể, nếu có nhiều hơn hai, hãy xem xét câu trả lời của Craig bằng mệnh đề Giá trị.


cú pháp dễ hiểu hơn: return (chọn minValue = case khi @@ param1 <@@ param2 sau đó @@ param1 other @@ param2 end). Ok điều này có thể không được bình thường hóa, tôi không biết. Nhưng nó dễ hiểu hơn nhiều và nên được bình thường hóa.
Softlion

1
Một lý do khác để thích câu trả lời của @ Craig dưới đây là do xử lý null. Nếu các giá trị được so sánh là null và một trong các giá trị được so sánh là null, trường hợp chuyển đổi được hiển thị có thể trả về null hoặc giá trị, tùy thuộc vào thứ tự của phép thử WHEN (trừ khi bạn thêm sử dụng ISNULL). Cách tiếp cận của Craig sẽ luôn thích lựa chọn giá trị không null có vẻ đúng hơn đối với tôi, ít nhất là trong trường hợp sử dụng hiện tại của tôi khi so sánh các ngày không có giá trị.
Nij

148

SQL Server 2012 và 2014 hỗ trợ chức năng IIF (cont, true, false). Vì vậy, để lựa chọn tối thiểu, bạn có thể sử dụng nó như

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

Mặc dù IIF chỉ là một cách viết tắt để viết CASE...WHEN...ELSE, nhưng nó dễ viết hơn.


8
IIFchỉ là một cú pháp đường cho CASE...WHEN...ELSE.
Salman A

55
Có thể là có. Nhưng dễ viết hơn.
Mert Gülsoy

1
@ MertGülsoy Và dễ đọc hơn, nên ở đầu danh sách ưu tiên của mọi người, ngay sau khi chính xác.
Daniel

118

Các giải pháp sử dụng CASE, IIF và UDF là đầy đủ, nhưng không thực tế khi mở rộng vấn đề sang trường hợp chung sử dụng nhiều hơn 2 giá trị so sánh. Giải pháp tổng quát trong SQL Server 2008+ sử dụng một ứng dụng lạ của mệnh đề VALUES:

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

Tín dụng do trang web này: http://sqlblog.com/bloss/jamie_thomson/archive/2012/01/20/use-values-clause-to-get-the-maximum-value-from-some-columns-sql- máy chủ-t-sql.aspx


12
Đây là câu trả lời hay nhất
FindOutIslamNow

nếu bạn muốn số khác không:MIN(x*(case x when 0 then null else 1 end))
mpag

Ngoại trừ MartinC đã đưa ra câu trả lời tương tự bốn năm trước đó và thực sự đã cho thấy nó với hơn hai giá trị ...
Auspex

4
Auspex, câu trả lời của MartinC không liên quan. Câu trả lời này không sử dụng công đoàn.
Craig

30

Tôi vừa gặp tình huống phải tìm tối đa 4 lựa chọn phức tạp trong một bản cập nhật. Với phương pháp này bạn có thể có bao nhiêu tùy thích!

Bạn cũng có thể thay thế các số bằng các lựa chọn theo mục đích

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

Cách sử dụng phức tạp hơn

 @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

Tôi chắc chắn một UDF có hiệu suất tốt hơn.


Tôi thích cái đó nhất vì nó là SQL cơ bản. Hơn nữa, UDF không cần thiết nhanh hơn. Đối với hầu hết các cửa hàng cột, mỗi thuộc tính (tôi giả sử bạn cũng sẽ lọc các thuộc tính) có thể được tính toán song song và chỉ tập hợp đủ điều kiện được liên kết. Vì vậy, công đoàn không chậm mỗi se.
Bouncner

đơn giản và tuyệt vời
ashleedawg

22

Đối với MySQL hoặc PostgreSQL 9.3+, cách tốt hơn là sử dụng các hàm LEASTGREATESThàm.

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

Với:

  • GREATEST(value [, ...]): Trả về đối số lớn nhất (giá trị tối đa) từ các giá trị được cung cấp
  • LEAST(value [, ...])Trả về đối số nhỏ nhất (giá trị tối thiểu) từ các giá trị được cung cấp

Liên kết tài liệu:


Điều này cũng hoạt động trong PostgreSQL (và đó chính xác là những gì tôi đang tìm kiếm :) Xem: postgresql.org/docs/9.5/static/fifts-conditable.html
Albert Vaca Cintora

1
Đây là câu trả lời tốt nhất cho đến nay.
Roberto Rodriguez

2
@RobertoRodriguez sẽ là tốt nhất nếu câu hỏi có MySQL hoặc PostgreQuery được gắn thẻ như một phần của câu hỏi. Câu hỏi cụ thể là về tsql vì vậy câu trả lời này không giúp ích gì cả.
Jmaurier

đây không phải là câu trả lời cho MSSQL
Mujah Maskey

13

Đây là một mẹo nếu bạn muốn tính toán tối đa (trường, 0):

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

trả về 0 nếu fieldâm, khác, trả về field.


3
Vì vậy, để tính toán tối thiểu (@a, @b), bạn có thể sử dụng:SELECT @a - ( ABS(@a-@b) + (@a-@b) ) / 2
scottyc

1
và đừng quên kiểu tràn;)
pkuderov

Đây có phải là tiết kiệm từ quan điểm chính xác điểm nổi? Có chắc chắn, rằng kết quả sẽ không bao giờ là một cái gì đó gần bằng không nhưng tiêu cực?
zuraff

6

Sử dụng câu lệnh CASE.

Ví dụ B trong trang này phải gần với những gì bạn đang cố gắng thực hiện:
http://msdn.microsoft.com/en-us/l Library / ms181765.aspx

Đây là mã từ trang:

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

Sử dụng bảng tạm thời để chèn phạm vi giá trị, sau đó chọn tối thiểu / tối đa của bảng tạm thời từ trong một thủ tục được lưu trữ hoặc UDF. Đây là một cấu trúc cơ bản, vì vậy hãy xem lại khi cần thiết.

Ví dụ:

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

Điều này hoạt động trong tối đa 5 ngày và xử lý null. Không thể làm cho nó hoạt động như một chức năng Nội tuyến.

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

Chỉ cần nhận ra rằng bạn không cần các khoản WHERE vì MIN sẽ loại bỏ Nulls.
Lawrence

2

Dựa trên logic / mã tuyệt vời từ mathematix và scottyc, tôi gửi:

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

Mặc dù việc chuyển từ hàm MIN của scottyc sang hàm MAX rõ ràng đối với tôi, nhưng không phải vậy, vì vậy tôi đã giải quyết nó và đưa nó vào đây: SELECT @a + (ABS (@ b- @ a) + ( @ b- @ a)) / 2. Các số được tạo ngẫu nhiên, trong khi không phải là bằng chứng, ít nhất nên thuyết phục những người hoài nghi rằng cả hai công thức đều đúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.