SQLで2つの値の最小値を取得する


180

2つの変数があります。1つはと呼ばれ、もう1つはとPaidThisMonth呼ばれOwedPastます。どちらもSQLのいくつかのサブクエリの結果です。2つのうち小さい方を選択して、タイトルの値として返すにはどうすればよいPaidForPastですか?

このMIN関数は変数ではなく列に対して機能します。


1
PostgresまたはMySQLを使用している場合は、@ Gil_Margolinの回答までスキップしてください。
Noumenon

回答:


127

使用事例:

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

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)

補遺:これは、可能な値が2つしかない場合に最適です。3つ以上ある場合は、値句を使用したクレイグの回答を検討してください。


よりわかりやすい構文:return(select minValue = case when @@ param1 <@@ param2 then @@ param1 else @@ param2 end)。これは正規化されていないかもしれませんが、わかりません。しかし、それははるかに理解しやすく、正規化する必要があります。
Softlion 2012年

1
以下の@Craigの回答を好むもう1つの理由は、null処理によるものです。比較される値がNULL可能であり、比較される値の1つがNULLの場合、WHENテストの順序に応じて(ISNULLの使用を追加しない限り)示されているスイッチケースがNULLまたは値を返す場合があります。Craigのアプローチでは、少なくとも現在の使用例では、null許容可能日付の比較において、nullでない値の選択が常により適切であるように思われます。
Nij

148

SQL Server 2012および2014は、IIF(cont、true、false)関数をサポートしています。したがって、最小限の選択では、次のように使用できます

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

一方でIIFは、書き込みのためだけの速記であるCASE...WHEN...ELSE、それは書き込みに簡単です。


8
IIFは単なるの構文糖ですCASE...WHEN...ELSE
Salman A

55
おそらくはい。しかし、書きやすい。
MertGülsoy、2015

1
@MertGülsoy読みやすく、正確性の直後に全員の優先順位リストの一番上にあるはずです。
ダニエル

118

CASE、IIF、およびUDFを使用するソリューションは適切ですが、問題を2つを超える比較値を使用する一般的なケースに拡張する場合、実用的ではありません。SQL Server 2008以降の一般化されたソリューションは、VALUES句の奇妙なアプリケーションを利用しています。

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- server-t-sql.aspx


12
これが最良の答えです
FindOutIslamNow 2017

最小値をゼロ以外にしたい場合:MIN(x*(case x when 0 then null else 1 end))
mpag

MartinCが4年前に同じ答えを出し、実際には2つ以上の値でそれを示した場合を
除いて

4
Auspex、MartinCの回答は無関係です。この回答では、共用体を使用していません。
クレイグ、

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なので、私はその1つが一番好きです。さらに、UDFは必ずしも高速ではありません。ほとんどの列ストアでは、各属性(属性をフィルター処理することも想定しています)は並列で計算でき、修飾セットのみが結合されます。だから組合はそれ自体遅いわけではない。
Bouncner、2016年

シンプルで素晴らしい。
ashleedawg 2018

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 2017

1
これは断然最良の答えです。
Roberto Rodriguez

2
@RobertoRodriguez質問にMySQLまたはPostgreSQLが質問の一部としてタグ付けされていると、最高です。問題は特にtsqlに関するものだったので、この回答はまったく役に立ちません。
Jmaurier

これはMSSQLの答えではありません
Mujah Maskey

13

maximum(field、0)を計算する場合のトリックは次のとおりです。

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

fieldが負の場合は0を返し、それ以外の場合はを返しますfield


3
したがって、最小値(@ a、@ b)を計算するには、次のように使用できますSELECT @a - ( ABS(@a-@b) + (@a-@b) ) / 2
。– scottyc

1
タイプオーバーフローを忘れないでください;)
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

一時テーブルを使用して値の範囲を挿入してから、ストアドプロシージャまたは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を処理します。それをインライン関数として機能させることができませんでした。

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

MINはNullを削除するので、WHERE句は必要ないことに気づきました。
ローレンス

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

scottycのMIN関数からMAX関数へのジャンプは私には明らかだったはずですが、そうではなかったので、それを解決してここに含めました:SELECT @a +(ABS(@ b- @ a)+( @ b- @ a))/ 2.ランダムに生成された数値は、証明ではありませんが、少なくとも両方の式が正しいことを懐疑論者に納得させる必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.