複数の列の最大値の行ごとに1つの値を返すにはどうすればよいですか:
テーブル名
[Number, Date1, Date2, Date3, Cost]
次のようなものを返す必要があります。
[Number, Most_Recent_Date, Cost]
クエリ?
複数の列の最大値の行ごとに1つの値を返すにはどうすればよいですか:
テーブル名
[Number, Date1, Date2, Date3, Cost]
次のようなものを返す必要があります。
[Number, Most_Recent_Date, Cost]
クエリ?
Max
T-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 句の派生テーブルとして。
これは古い答えであり、多くの点で壊れています。
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
MySQL、PostgreSQL、またはOracleを使用している場合は、
SELECT GREATEST(col1, col2 ...) FROM table
さらに 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
UNPIVOT
)SELECT number ,
MAX(dDate) maxDate ,
cost
FROM dates UNPIVOT ( dDate FOR nDate IN ( Date1, Date2,
Date3 ) ) as u
GROUP BY number ,
cost
GO
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
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
以下の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
スカラー関数はあらゆる種類のパフォーマンスの問題を引き起こすため、可能であればロジックをインライン テーブル値関数にラップすることをお勧めします。これは、最大 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)
)
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
SELECT
CASE
WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
WHEN Date2 >= Date3 THEN Date2
ELSE Date3
END AS MostRecentDate
これは書き出すのが少し簡単で、case ステートメントが順番に評価されるため、評価ステップをスキップします。
残念ながら、 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
問題: エンティティに与えられる最低レート値を選択する 要件: 代理店レートは 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
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
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
使用してみてくださいUNPIVOT
:
SELECT MAX(MaxDt) MaxDt
FROM tbl
UNPIVOT
(MaxDt FOR E IN
(Date1, Date2, Date3)
)AS unpvt;
日付を渡す関数を作成し、その関数を次のように 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
終わり