SQL MAX из нескольких столбцов?
Как вы возвращаете 1 значение в строку максимум нескольких столбцов:
TableName
[Number, Date1, Date2, Date3, Cost]
мне нужно вернуть что-то вроде этого:
[Number, Most_Recent_Date, Cost]
запрос?
20 ответов
Ну, вы можете использовать оператор 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 и выше, вы можете рассмотреть более простой ответ Свена ниже.]
вот еще одно хорошее решение для Max
функциональность с использованием T-SQL и SQL Server
SELECT [Other Fields],
(SELECT Max(v)
FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MaxDate]
FROM [YourTableName]
есть еще 3 метода, где UNPIVOT
(1) является самым быстрым, а затем моделируется 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
любой из двух образцов ниже будет работать:
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
второй является дополнением к 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
скалярная функция вызывает всевозможные проблемы с производительностью, поэтому лучше обернуть логику во встроенную табличную функцию, если это возможно. Это функция, которую я использовал для замены некоторых пользовательских функций, которые выбрали даты Min / Max из списка до десяти дат. При тестировании на моем наборе данных из 1 миллиона строк скалярная функция заняла более 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
для T-SQL (MSSQL 2008+)
SELECT
(SELECT
MAX(MyMaxName)
FROM ( VALUES
(MAX(iSortCode)),
(MAX(Field2))
) MyAlias(MyMaxName)
)
FROM MyTable1
SELECT
CASE
WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
WHEN Date2 >= Date3 THEN Date2
ELSE Date3
END AS MostRecentDate
это немного легче записать и пропускает шаги оценки, поскольку оператор case оценивается по порядку.
к сожалению ответ Лассе, хотя, казалось бы, очевидно, имеет изъян. Он не может обрабатывать значения NULL. Любое одно значение NULL приводит к возврату 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
использование перекрестного применения (для 2005+) ....
SELECT MostRecentDate
FROM SourceTable
CROSS APPLY (SELECT MAX(d) MostRecentDate FROM (VALUES (Date1), (Date2), (Date3)) AS a(d)) md
из 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
пожалуйста, попробуйте использовать 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
( @Типа smalldatetime дата1 , @Smalldatetime из дата2 , @Дата3 типа smalldatetime ) Возвращает тип данных smalldatetime КАК НАЧИНАТЬ Объявить @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
конец
на основе ScottPletcher решение от http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_24204894.html Я создал набор функций (например , GetMaxOfDates3, GetMaxOfDates13), чтобы найти максимум до 13 значений даты, используя UNION ALL. См.функция T-SQL, чтобы получить максимум значений из той же строки Однако я не рассматривал решение UNPIVOT на момент написания этих функций
другой способ использовать СЛУЧАЙ, КОГДА
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
Я не знаю, находится ли он на SQL и т. д... на M$ACCESS help есть функция под названием MAXA(Value1;Value2;...)
Это должно сделать такое.
Надежда может помочь кому-то.
P. D.: значения могут быть столбцами или вычисленными и т. д.
вот хорошее решение:
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