454

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

テーブル名

[Number, Date1, Date2, Date3, Cost]

次のようなものを返す必要があります。

[Number, Most_Recent_Date, Cost]

クエリ?

4

23 に答える 23

970

MaxT-SQL と SQL Server を使用した機能の別の優れたソリューションを次に示します。

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

Values はTable Value Constructorです。

"テーブルに構築される一連の行値式を指定します。Transact-SQL テーブル値コンストラクターを使用すると、単一の DML ステートメントで複数行のデータを指定できます。テーブル値コンストラクターは、 INSERT ... VALUES ステートメント、または MERGE ステートメントの USING 句または FROM 句の派生テーブルとして。

于 2011-07-29T10:11:27.257 に答える
189

これは古い答えであり、多くの点で壊れています。

https://stackoverflow.com/a/6871572/194653を参照してください。より多くの賛成票があり、SQL Server 2008 以降で動作し、null などを処理します。

オリジナルだが問題のある答え

さて、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
于 2008-09-16T10:30:31.330 に答える
188

MySQL、PostgreSQL、またはOracleを使用している場合は、

SELECT GREATEST(col1, col2 ...) FROM table
于 2008-12-01T19:16:33.650 に答える
68

さらに 3 つの方法があり、UNPIVOT(1) が群を抜いて最速であり、続いて Simulated Unpivot (3) が続きます。これは (1) よりもはるかに遅いですが、(2) よりも高速です。

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
于 2009-09-09T07:15:26.110 に答える
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 
于 2008-09-16T10:49:13.067 に答える
17

スカラー関数はあらゆる種類のパフォーマンスの問題を引き起こすため、可能であればロジックをインライン テーブル値関数にラップすることをお勧めします。これは、最大 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)
)
于 2011-02-07T13:58:07.527 に答える
10
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
于 2010-11-29T22:51:23.910 に答える
6
SELECT 
    CASE 
        WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1 
        WHEN Date2 >= Date3 THEN Date2 
        ELSE Date3
    END AS MostRecentDate 

これは書き出すのが少し簡単で、case ステートメントが順番に評価されるため、評価ステップをスキップします。

于 2010-11-29T22:03:29.200 に答える
5

残念ながら、 Lasse の答えは一見明白ですが、重大な欠陥があります。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
于 2012-01-23T12:42:05.097 に答える
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 

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

于 2012-05-31T10:28:56.020 に答える
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
于 2008-12-01T19:36:58.633 に答える
1

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

CREATE FUNCTION GetMaxOfDates13 (
@value01 DateTime = NULL,  
@value02 DateTime = NULL,
@value03 DateTime = NULL,
@value04 DateTime = NULL,
@value05 DateTime = NULL,
@value06 DateTime = NULL,
@value07 DateTime = NULL,
@value08 DateTime = NULL,
@value09 DateTime = NULL,
@value10 DateTime = NULL,
@value11 DateTime = NULL,
@value12 DateTime = NULL,
@value13 DateTime = NULL
)
RETURNS DateTime
AS
BEGIN
RETURN (
SELECT TOP 1 value
FROM (
SELECT @value01 AS value UNION ALL
SELECT @value02 UNION ALL
SELECT @value03 UNION ALL
SELECT @value04 UNION ALL
SELECT @value05 UNION ALL
SELECT @value06 UNION ALL
SELECT @value07 UNION ALL
SELECT @value08 UNION ALL
SELECT @value09 UNION ALL
SELECT @value10 UNION ALL
SELECT @value11 UNION ALL
SELECT @value12 UNION ALL
SELECT @value13
) AS [values]
ORDER BY value DESC    
)
END –FUNCTION
GO
CREATE FUNCTION GetMaxOfDates3 (
@value01 DateTime = NULL,  
@value02 DateTime = NULL,
@value03 DateTime = NULL
)
RETURNS DateTime
AS
BEGIN
RETURN dbo.GetMaxOfDates13(@value01,@value02,@value03,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)
END –FUNCTION
于 2011-07-11T12:42:59.330 に答える
1

使用してみてくださいUNPIVOT

SELECT MAX(MaxDt) MaxDt
   FROM tbl 
UNPIVOT
   (MaxDt FOR E IN 
      (Date1, Date2, Date3)
)AS unpvt;
于 2014-05-26T06:52:50.270 に答える
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

終わり

于 2011-01-14T19:40:58.033 に答える