複数列のSQL MAX?


372

複数の列の最大値の行ごとに1つの値を返すにはどうすればよいですか。

TableName

[Number, Date1, Date2, Date3, Cost]

私はこのようなものを返す必要があります:

[Number, Most_Recent_Date, Cost]

クエリ?

回答:


161

さて、あなたはCASEステートメントを使うことができます:

SELECT
    CASE
        WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
        WHEN Date2 >= Date1 AND Date2 >= Date3 THEN Date2
        WHEN Date3 >= Date1 AND Date3 >= Date2 THEN Date3
        ELSE                                        Date1
    END AS MostRecentDate

[Microsoft SQL Server 2008以降の場合は、以下のSvenのより簡単な回答を検討してください。]


11
使用すれば十分ではないでしょうWHEN Date1 > Date2 AND Date1 > Date3 THEN Date1; WHEN Date2 > Date3 THEN Date3; ELSE Date3か?
Trebが2011年

21
明白な答えですが、それはNULL値では機能せず、それを修正しようとすると非常に面倒になります。
幻滅2012年

5
この古い投稿をネクロしますが、各日付をCOALESCEにラップしてNULLを処理できます。日付1> COALESCE(日付2、 '')AND日付1> = COALESCE(Date3、 '')THEN Date3(ときの他のために同じことを行う)=:ステートメントは、次にようになり、それらの一つ
ビル・Sambrone

MySQLの方法を探してここに来た人のために、bajafresh4life返信@に見てみましょう:stackoverflow.com/a/331873/1412157
LucaM

2
ところで、Date3> Date1であっても、Date2がnullの場合、Date1を返します。
jumxozizi 2017

853

MaxT-SQLとSQL Serverを使用する機能のもう1つの優れたソリューションを次に示します

SELECT [Other Fields],
  (SELECT Max(v) 
   FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MaxDate]
FROM [YourTableName]

47
SQLのバージョンが> = 2008でなければなりません
ダニエル・

10
これは2008で非常にうまく機能し、NULLを処理します。とても良い解決策です。
nycdan

10
@Cheburek:value(v)から、「value」は仮想テーブルのエイリアスで、「v」は日付値の仮想列の名前です。
ジョナスリンカーン

2
これは素晴らしいです。このValue()仮想テーブルのドキュメントはどこにありますか?
My Other Me

33
最初はVALUE(v)も理解していませんでした。VALUEを理解するには、仮想1列テーブルを作成する次のクエリを試してください:SELECT * FROM(VALUES(1)、(5)、(1))as listOfValues(columnName)そして、仮想2列テーブルを作成するこのクエリ: SELECT * FROM(VALUES(1,2)、(5,3)、(1,4))as tableOfValues(columnName1、ColumnName2)これで、そのサンプルクエリにAS値(v)が含まれている理由を理解できます。それは、この場合には35で、最大値を選択しますAS allCurrents(currentValues)((35)、VALUES(12)、(25))から、最大としてSELECT MAX(currentValues):私の最後のクエリは、このように見えた
ジャクソン

148

MySQLを使用している場合は、

SELECT GREATEST(col1, col2 ...) FROM table

41
タグはsqlserverです
Codewerks 2008

104
確かに、しかしMySQLに関連してこの質問を見つける人々にとって、それは非常に役立つ答えです。
philfreo 2010

4
PostgreSQLの8.1以降でも使用できます。
Frozen Flame

4
この回答を参照してNULLのうまく処理されませんが、あなたはあなたの列の値の周り(COL1、0)を合体した場合、あなたはガスで調理をすることがありますstackoverflow.com/questions/9831851/...を
スタン・クイン

そして、このソリューションはどう
ですか

64

さらに3つの方法があり、UNPIVOT(1)が断然最速で、その後に(1)よりはるかに遅いが(2)よりも速いシミュレートされたアンピボット(3)が続きます。

CREATE TABLE dates
    (
      number INT PRIMARY KEY ,
      date1 DATETIME ,
      date2 DATETIME ,
      date3 DATETIME ,
      cost INT
    )

INSERT  INTO dates
VALUES  ( 1, '1/1/2008', '2/4/2008', '3/1/2008', 10 )
INSERT  INTO dates
VALUES  ( 2, '1/2/2008', '2/3/2008', '3/3/2008', 20 )
INSERT  INTO dates
VALUES  ( 3, '1/3/2008', '2/2/2008', '3/2/2008', 30 )
INSERT  INTO dates
VALUES  ( 4, '1/4/2008', '2/1/2008', '3/4/2008', 40 )
GO

ソリューション1(UNPIVOT

SELECT  number ,
        MAX(dDate) maxDate ,
        cost
FROM    dates UNPIVOT ( dDate FOR nDate IN ( Date1, Date2,
                                            Date3 ) ) as u
GROUP BY number ,
        cost 
GO

ソリューション2(行ごとのサブクエリ)

SELECT  number ,
        ( SELECT    MAX(dDate) maxDate
          FROM      ( SELECT    d.date1 AS dDate
                      UNION
                      SELECT    d.date2
                      UNION
                      SELECT    d.date3
                    ) a
        ) MaxDate ,
        Cost
FROM    dates d
GO

ソリューション3(シミュレーションUNPIVOT

;WITH    maxD
          AS ( SELECT   number ,
                        MAX(CASE rn
                              WHEN 1 THEN Date1
                              WHEN 2 THEN date2
                              ELSE date3
                            END) AS maxDate
               FROM     dates a
                        CROSS JOIN ( SELECT 1 AS rn
                                     UNION
                                     SELECT 2
                                     UNION
                                     SELECT 3
                                   ) b
               GROUP BY Number
             )
    SELECT  dates.number ,
            maxD.maxDate ,
            dates.cost
    FROM    dates
            INNER JOIN MaxD ON dates.number = maxD.number
GO

DROP TABLE dates
GO

1
いいね。私はPIVOTおよびUNPIVOTオペレーターに気づいていませんでした。
Sako73、2009

SQL Serverのどのバージョンがピボット/アンピボットをサポートしているのですか?
幻滅2012年

1
COMPATIBILITY_LEVELが90に設定された@CraigYoung SQL Server 2005
Paul Syfrett

18

以下の2つのサンプルのどちらでも機能します。

SELECT  MAX(date_columns) AS max_date
FROM    ( (SELECT   date1 AS date_columns
           FROM     data_table         )
          UNION
          ( SELECT  date2 AS date_columns
            FROM    data_table
          )
          UNION
          ( SELECT  date3 AS date_columns
            FROM    data_table
          )
        ) AS date_query

2つ目は、lassevkの回答のアドオンです。

SELECT  MAX(MostRecentDate)
FROM    ( SELECT    CASE WHEN date1 >= date2
                              AND date1 >= date3 THEN date1
                         WHEN date2 >= date1
                              AND date2 >= date3 THEN date2
                         WHEN date3 >= date1
                              AND date3 >= date2 THEN date3
                         ELSE date1
                    END AS MostRecentDate
          FROM      data_table
        ) AS date_query 

最初の答えは良いですが、かなり単純化することができます。2番目の答えはNULL値では機能しません。その問題を修正しようとすると、非常に面倒になります。
幻滅2012年

UNIONではなくUNION ALLを使用して、不要な暗黙のDISTINCT操作を回避する必要があります。
JamieSee 2016年

17

T-SQL(MSSQL 2008+)の場合

SELECT
  (SELECT
     MAX(MyMaxName) 
   FROM ( VALUES 
            (MAX(Field1)), 
            (MAX(Field2)) 
        ) MyAlias(MyMaxName)
  ) 
FROM MyTable1

9
DECLARE @TableName TABLE (Number INT, Date1 DATETIME, Date2 DATETIME, Date3 DATETIME, Cost MONEY)

INSERT INTO @TableName 
SELECT 1, '20000101', '20010101','20020101',100 UNION ALL
SELECT 2, '20000101', '19900101','19980101',99 

SELECT Number,
       Cost  ,
       (SELECT MAX([Date])
       FROM    (SELECT Date1 AS [Date]
               UNION ALL
               SELECT Date2
               UNION ALL
               SELECT Date3
               )
               D
       )
       [Most Recent Date]
FROM   @TableName

私にとってはどのSQLバージョンでも機能しました。素晴らしい解決策
Kirill

9

スカラー関数はあらゆる種類のパフォーマンスの問題を引き起こすため、可能であれば、ロジックをインラインテーブル値関数にラップすることをお勧めします。これは、最大10の日付のリストから最小/最大日付を選択したユーザー定義関数を置き換えるために使用した関数です。100万行のデータセットでテストしたところ、スカラー関数はクエリを終了する前に15分以上かかりました。インラインTVFは1分かかりました。これは、結果セットを一時テーブルに選択するのと同じ時間です。これを使用するには、SELECTまたはCROSS APPLYのサブクエリから関数を呼び出します。

CREATE FUNCTION dbo.Get_Min_Max_Date
(
    @Date1  datetime,
    @Date2  datetime,
    @Date3  datetime,
    @Date4  datetime,
    @Date5  datetime,
    @Date6  datetime,
    @Date7  datetime,
    @Date8  datetime,
    @Date9  datetime,
    @Date10 datetime
)
RETURNS TABLE
AS
RETURN
(
    SELECT      Max(DateValue)  Max_Date,
                Min(DateValue)  Min_Date
    FROM        (
                    VALUES  (@Date1),
                            (@Date2),
                            (@Date3),
                            (@Date4),
                            (@Date5),
                            (@Date6),
                            (@Date7),
                            (@Date8),
                            (@Date9),
                            (@Date10)
                )   AS Dates(DateValue)
)

5
SELECT 
    CASE 
        WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1 
        WHEN Date2 >= Date3 THEN Date2 
        ELSE Date3
    END AS MostRecentDate 

これは少し書きやすくなり、caseステートメントが順番に評価されるため、評価手順がスキップされます。


4
注意してください。Date2がNULLの場合、答えはDate3になります。Date1が大きい場合でも。
幻滅2012年

4

残念ながらラッセの答えは一見明白ですが、重大な欠陥があります。NULL値は処理できません。NULL値が1つでもあると、Date1が返されます。残念ながら、その問題を修正しようとすると、非常に面倒になりがちで、4つ以上の値にうまく対応できません。

databyssの最初の回答は良さそうであり、現在もそうです。ただし、単一のテーブルからのより単純な3つの値ではなく、マルチテーブル結合からの3つの値に答えが容易に外挿できるかどうかは明確ではありませんでした。最大3つの列を取得するためだけに、このようなクエリをサブクエリに変換することは避けたかったのですが、databyssの優れたアイデアを少し整理できると確信していました。

さて、これ以上苦労せずに、これが私の解決策です(databyssのアイデアから派生したもの)。
クロス結合を使用して定数を選択し、マルチテーブル結合の効果をシミュレートします。注意すべき重要なことは、必要なすべてのエイリアスが正しく引き継がれ(常にそうであるとは限らない)、これにより、パターンが非常にシンプルになり、追加の列を通じてかなりスケーラブルになります。

DECLARE @v1 INT ,
        @v2 INT ,
        @v3 INT
--SET @v1 = 1 --Comment out SET statements to experiment with 
              --various combinations of NULL values
SET @v2 = 2
SET @v3 = 3

SELECT  ( SELECT    MAX(Vals)
          FROM      ( SELECT    v1 AS Vals
                      UNION
                      SELECT    v2
                      UNION
                      SELECT    v3
                    ) tmp
          WHERE     Vals IS NOT NULL -- This eliminates NULL warning

        ) AS MaxVal
FROM    ( SELECT    @v1 AS v1
        ) t1
        CROSS JOIN ( SELECT @v2 AS v2
                   ) t2
        CROSS JOIN ( SELECT @v3 AS v3
                   ) t3

4

問題:エンティティに与えられた最小レート値を選択する要件:代理店レートはnullにすることができます

[MinRateValue] = 
CASE 
   WHEN ISNULL(FitchRating.RatingValue, 100) < = ISNULL(MoodyRating.RatingValue, 99) 
   AND  ISNULL(FitchRating.RatingValue, 100) < = ISNULL(StandardPoorsRating.RatingValue, 99) 
   THEN FitchgAgency.RatingAgencyName

   WHEN ISNULL(MoodyRating.RatingValue, 100) < = ISNULL(StandardPoorsRating.RatingValue , 99)
   THEN MoodyAgency.RatingAgencyName

   ELSE ISNULL(StandardPoorsRating.RatingValue, 'N/A') 
END 

ナットからのこの答えに触発されました


3

SQL Server 2005を使用している場合は、UNPIVOT機能を使用できます。以下は完全な例です。

create table dates 
(
  number int,
  date1 datetime,
  date2 datetime,
  date3 datetime 
)

insert into dates values (1, '1/1/2008', '2/4/2008', '3/1/2008')
insert into dates values (1, '1/2/2008', '2/3/2008', '3/3/2008')
insert into dates values (1, '1/3/2008', '2/2/2008', '3/2/2008')
insert into dates values (1, '1/4/2008', '2/1/2008', '3/4/2008')

select max(dateMaxes)
from (
  select 
    (select max(date1) from dates) date1max, 
    (select max(date2) from dates) date2max,
    (select max(date3) from dates) date3max
) myTable
unpivot (dateMaxes For fieldName In (date1max, date2max, date3max)) as tblPivot

drop table dates

1
UNIONの例のほうが好きだと思います。
ランスフィッシャー

「いくつかの列の最大値の行
ごとに1つの

3

CROSS APPLYの使用(2005以降)....

SELECT MostRecentDate 
FROM SourceTable
    CROSS APPLY (SELECT MAX(d) MostRecentDate FROM (VALUES (Date1), (Date2), (Date3)) AS a(d)) md

3

SQL Server 2012以降では、IIFを使用できます。

 DECLARE @Date1 DATE='2014-07-03';
 DECLARE @Date2 DATE='2014-07-04';
 DECLARE @Date3 DATE='2014-07-05';

 SELECT IIF(@Date1>@Date2,
        IIF(@Date1>@Date3,@Date1,@Date3),
        IIF(@Date2>@Date3,@Date2,@Date3)) AS MostRecentDate

かなりいいですが、nullは処理しません。例:DECLARE @Date1 DATE='2014-08-01'; DECLARE @Date2 DATE=null; DECLARE @Date3 DATE='2014-07-05'; /*this gets returned*/
jumxozizi 2018年

:私たちは、このようなヌル扱うことができるselect IIF(@Date1 > @Date2 or @Date2 is null, IIF(@Date1 > @Date3 or @Date3 is null, @Date1, @Date3), IIF(@Date2 > @Date3 or @Date3 is null, @Date2, @Date3)) as MostRecentDate
jumxozizi

1

使用してみてくださいUNPIVOT

SELECT MAX(MaxDt) MaxDt
   FROM tbl 
UNPIVOT
   (MaxDt FOR E IN 
      (Date1, Date2, Date3)
)AS unpvt;

1

私はケースタイムに基づいたソリューションを好みます。私の想定では、クロス適用、values()、カスタム関数などの他の可能なソリューションと比較して、パフォーマンスの低下に与える影響が最も少ないはずです。

以下は、ほとんどの可能なテストケースでnull値を処理する場合のバージョンです。

SELECT
    CASE 
        WHEN Date1 > coalesce(Date2,'0001-01-01') AND Date1 > coalesce(Date3,'0001-01-01') THEN Date1 
        WHEN Date2 > coalesce(Date3,'0001-01-01') THEN Date2 
        ELSE Date3
    END AS MostRecentDate
    , *
from 
(values
     (  1, cast('2001-01-01' as Date), cast('2002-01-01' as Date), cast('2003-01-01' as Date))
    ,(  2, cast('2001-01-01' as Date), cast('2003-01-01' as Date), cast('2002-01-01' as Date))
    ,(  3, cast('2002-01-01' as Date), cast('2001-01-01' as Date), cast('2003-01-01' as Date))
    ,(  4, cast('2002-01-01' as Date), cast('2003-01-01' as Date), cast('2001-01-01' as Date))
    ,(  5, cast('2003-01-01' as Date), cast('2001-01-01' as Date), cast('2002-01-01' as Date))
    ,(  6, cast('2003-01-01' as Date), cast('2002-01-01' as Date), cast('2001-01-01' as Date))
    ,( 11, cast(NULL         as Date), cast('2002-01-01' as Date), cast('2003-01-01' as Date))
    ,( 12, cast(NULL         as Date), cast('2003-01-01' as Date), cast('2002-01-01' as Date))
    ,( 13, cast('2003-01-01' as Date), cast(NULL         as Date), cast('2002-01-01' as Date))
    ,( 14, cast('2002-01-01' as Date), cast(NULL         as Date), cast('2003-01-01' as Date))
    ,( 15, cast('2003-01-01' as Date), cast('2002-01-01' as Date), cast(NULL         as Date))
    ,( 16, cast('2002-01-01' as Date), cast('2003-01-01' as Date), cast(NULL         as Date))
    ,( 21, cast('2003-01-01' as Date), cast(NULL         as Date), cast(NULL         as Date))
    ,( 22, cast(NULL         as Date), cast('2003-01-01' as Date), cast(NULL         as Date))
    ,( 23, cast(NULL         as Date), cast(NULL         as Date), cast('2003-01-01' as Date))
    ,( 31, cast(NULL         as Date), cast(NULL         as Date), cast(NULL         as Date))

) as demoValues(id, Date1,Date2,Date3)
order by id
;

結果は次のとおりです。

MostRecent    id   Date1      Date2      Date3
2003-01-01    1    2001-01-01 2002-01-01 2003-01-01
2003-01-01    2    2001-01-01 2003-01-01 2002-01-01
2003-01-01    3    2002-01-01 2001-01-01 2002-01-01
2003-01-01    4    2002-01-01 2003-01-01 2001-01-01
2003-01-01    5    2003-01-01 2001-01-01 2002-01-01
2003-01-01    6    2003-01-01 2002-01-01 2001-01-01
2003-01-01    11   NULL       2002-01-01 2003-01-01
2003-01-01    12   NULL       2003-01-01 2002-01-01
2003-01-01    13   2003-01-01 NULL       2002-01-01
2003-01-01    14   2002-01-01 NULL       2003-01-01
2003-01-01    15   2003-01-01 2002-01-01 NULL
2003-01-01    16   2002-01-01 2003-01-01 NULL
2003-01-01    21   2003-01-01 NULL       NULL
2003-01-01    22   NULL       2003-01-01 NULL
2003-01-01    23   NULL       NULL       2003-01-01
NULL          31   NULL       NULL       NULL

1
ああ神様、ありがとうございます!私は非常に多くの時間を費やしてモンスターのフォーミュラを作り、それでもヌルを与えましたが、今ではトンネルの終わりに光が見えます。
最大S.

0

日付を渡す関数を作成し、以下のように関数をselectステートメントに追加できます。数値、dbo.fxMost_Recent_Date(Date1、Date2、Date3)、コストを選択します

create FUNCTION  fxMost_Recent_Date 

(@ Date1 smalldatetime、@ Date2 smalldatetime、@ Date3 smalldatetime)RETURNS smalldatetime AS BEGIN DECLARE @Result smalldatetime

declare @MostRecent smalldatetime

set @MostRecent='1/1/1900'

if @Date1>@MostRecent begin set @MostRecent=@Date1 end
if @Date2>@MostRecent begin set @MostRecent=@Date2 end
if @Date3>@MostRecent begin set @MostRecent=@Date3 end
RETURN @MostRecent

終わり


0

http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_24204894.htmlScottPletcherのソリューションに基づいて、 最大値を見つけるための一連の関数(例:GetMaxOfDates3、GetMaxOfDates13)を作成しましたUNION ALLを使用して、最大13の日付値の。同じ行から最大値を取得するT-SQL関数を参照してください。 ただし、これらの関数を作成する時点では、UNPIVOTソリューションについては考慮していません。


0

CASE WHENを使用する別の方法

SELECT CASE true 
       WHEN max(row1) >= max(row2) THEN CASE true WHEN max(row1) >= max(row3) THEN max(row1) ELSE max(row3) end ELSE
       CASE true WHEN max(row2) >= max(row3) THEN max(row2) ELSE max(row3) END END
FROM yourTable

-1

ここに画像の説明を入力してください上記のテーブルは、列としてsalary1、salary2、salary3、salary4を持つ従業員の給与テーブルです。以下のクエリは、4つの列から最大値を返します

select  
 (select Max(salval) from( values (max(salary1)),(max(salary2)),(max(salary3)),(max(Salary4)))alias(salval)) as largest_val
 from EmployeeSalary

上記のクエリを実行すると、出力がmaximum_val(10001)として出力されます

上記のクエリのロジックは次のとおりです。

select Max(salvalue) from(values (10001),(5098),(6070),(7500))alias(salvalue)

出力は10001になります


これは、@ svenによって2011
Luuk

-3

ここに良い解決策があります:

CREATE function [dbo].[inLineMax] (@v1 float,@v2 float,@v3 float,@v4 float)
returns float
as
begin
declare @val float
set @val = 0 
declare @TableVal table
(value float )
insert into @TableVal select @v1
insert into @TableVal select @v2
insert into @TableVal select @v3
insert into @TableVal select @v4

select @val= max(value) from @TableVal

return @val
end 

-3

それがSQLなどにあるかどうかはわかりません... M $ ACCESSヘルプには、MAXA(Value1;Value2;...)そのようなことを行うはずの呼び出された関数があります。

希望は誰かを助けることができます。

PD:値は列または計算されたものなどです。


1
Microsoft Accessは完全に異なる製品です。その上、あなたはそのような機能のあなたの主張を調達することができますか?これについてAccessで見たり聞いたりしたことはありません。
deutschZuid 2016

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