it-swarm-vi.tech

SQL MAX của nhiều cột?

Làm thế nào để bạn trả về 1 giá trị trên mỗi hàng của tối đa một số cột:

Tên bảng

[Number, Date1, Date2, Date3, Cost]

Tôi cần phải trả lại một cái gì đó như thế này:

[Number, Most_Recent_Date, Cost]

Truy vấn?

317
BenB

Chà, bạn có thể sử dụng câu lệnh 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

[Đối với Microsoft SQL Server 2008 trở lên, bạn có thể xem xét câu trả lời đơn giản hơn của Sven bên dưới.]

140

Đây là một giải pháp Nice khác cho chức năng Max bằng T-SQL và SQL Server

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

Nếu bạn đang sử dụng MySQL, bạn có thể sử dụng

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

Có thêm 3 phương thức trong đó UNPIVOT (1) là nhanh nhất cho đến nay, theo sau là Mô phỏng không xoay vòng (3) chậm hơn nhiều so với (1) nhưng vẫn nhanh hơn (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

Giải pháp 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

Giải pháp 2 (Truy vấn phụ trên mỗi hàng)

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

Giải pháp 3 (Mô phỏng 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
57
Niikola

Một trong hai mẫu dưới đây sẽ hoạt động:

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

Thứ hai là một tiện ích bổ sung cho lassevk's answer.

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 
16
databyss

Hàm vô hướng gây ra tất cả các loại vấn đề về hiệu năng, vì vậy tốt hơn hết là bọc logic vào Hàm nội tuyến có giá trị nếu có thể. Đây là chức năng tôi đã sử dụng để thay thế một số Hàm do người dùng xác định đã chọn ngày tối thiểu/tối đa từ danh sách tối đa mười ngày. Khi được kiểm tra trên tập dữ liệu 1 triệu hàng của tôi, Hàm vô hướng mất hơn 15 phút trước khi tôi giết truy vấn, TVF nội tuyến mất 1 phút, cùng thời gian với việc chọn kết quả vào bảng tạm thời. Để sử dụng lệnh này, hãy gọi hàm từ một truy vấn con trong CHỌN hoặc ỨNG DỤNG CROSS.

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)
)
9
MartinC
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
8
Martin Smith

Đối với T-SQL (MSSQL 2008+)

SELECT
  (SELECT
     MAX(MyMaxName) 
   FROM ( VALUES 
            (MAX(iSortCode)), 
            (MAX(Field2)) 
        ) MyAlias(MyMaxName)
  ) 
FROM MyTable1
6
doker
SELECT 
    CASE 
        WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1 
        WHEN Date2 >= Date3 THEN Date2 
        ELSE Date3
    END AS MostRecentDate 

Điều này hơi dễ viết ra và bỏ qua các bước đánh giá vì tuyên bố trường hợp được đánh giá theo thứ tự.

5
Nat

Thật không may Câu trả lời của Lasse , mặc dù có vẻ rõ ràng, có một lỗ hổng quan trọng. Nó không thể xử lý các giá trị NULL. Bất kỳ giá trị NULL duy nhất nào dẫn đến Date1 được trả về. Thật không may, bất kỳ nỗ lực nào để khắc phục vấn đề đó có xu hướng trở nên cực kỳ lộn xộn và không mở rộng thành 4 hoặc nhiều giá trị rất độc đáo.

câu trả lời đầu tiên của databyss nhìn (và là) tốt. Tuy nhiên, không rõ liệu câu trả lời có dễ dàng ngoại suy thành 3 giá trị từ phép nối nhiều bảng thay vì 3 giá trị đơn giản hơn từ một bảng không. Tôi muốn tránh biến một truy vấn như vậy thành truy vấn phụ chỉ để có tối đa 3 cột, tôi cũng khá chắc chắn rằng ý tưởng tuyệt vời của cơ sở dữ liệu có thể được làm sạch một chút.

Vì vậy, không có gì khó chịu, đây là giải pháp của tôi (xuất phát từ ý tưởng của databyss).
Nó sử dụng các phép nối chéo chọn các hằng số để mô phỏng hiệu ứng của phép nối nhiều bảng. Điều quan trọng cần lưu ý là tất cả các bí danh cần thiết thực hiện chính xác (điều này không phải luôn luôn như vậy) và điều này giữ cho mẫu khá đơn giản và có thể mở rộng khá thông qua các cột bổ sung.

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
Disillusioned

Vấn đề: chọn giá trị tỷ lệ tối thiểu được cung cấp cho một thực thể Yêu cầu: Tỷ lệ đại lý có thể là 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 

Lấy cảm hứng từ câu trả lời này từ Nat

4
Luis Miguel Rosa

Sử dụng CROSS ỨNG DỤNG (cho năm 2005 trở lên) ....

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

Từ SQL Server 2012, chúng ta có thể sử dụng 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
3
abdulbasit

Nếu bạn đang sử dụng SQL Server 2005, bạn có thể sử dụng tính năng UNPIVOT. Dưới đây là một ví dụ đầy đủ:

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
3
Lance Fisher

Vui lòng thử sử dụng UNPIVOT:

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

Tôi có một bảng có tên là TblItem nếu tôi muốn lấy Id lớn nhất. Tôi sử dụng mã sau đây.

select MAX(Id) from TblItem
0
Diako Hasani

Tôi thích các giải pháp dựa trên trường hợp khi, giả định của tôi là nó sẽ có tác động ít nhất đến việc giảm hiệu suất có thể so với các giải pháp có thể khác như các giải pháp áp dụng chéo, giá trị (), chức năng tùy chỉnh, v.v.

Đây là phiên bản case-when xử lý các giá trị null với hầu hết các trường hợp thử nghiệm có thể:

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
;

và kết quả là:

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
0
Robert Lujo

Một cách khác để sử dụng TRƯỜNG HỢP KHI  

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
0
M.A.Bell

Dựa trên giải pháp của ScottPletcher 'từ http://www.experts-exchange.com/Microsoft/Development/MS-Query-Server/Q_24204894.html Tôi đã tạo một bộ của các hàm (ví dụ: GetMaxOfDates3, GetMaxOfDates13) để tìm tối đa tối đa 13 giá trị Ngày bằng UNION ALL . Xem Hàm T-SQL để lấy tối đa các giá trị từ cùng một hàng xem xét giải pháp UNPIVOT tại thời điểm viết các chức năng này 

0
Michael Freidgeim

Bạn có thể tạo một hàm trong đó bạn chuyển ngày và sau đó thêm hàm vào câu lệnh chọn như bên dưới . Chọn Number, dbo.fxMost_Recent_Date (Date1, Date2, Date3), Cost

create FUNCTION  fxMost_Recent_Date 

( @ Date1 smalldatetime, @ Date2 smalldatetime, @ Date3 smalldatetime ) QUAY LẠI thời gian nhỏ AS KHAI THÁC @Result smalldatetime

declare @MostRecent smalldatetime

set @MostRecent='1/1/1900'

if @Date1>@MostRecent begin set @[email protected] end
if @Date2>@MostRecent begin set @[email protected] end
if @Date3>@MostRecent begin set @[email protected] end
RETURN @MostRecent

KẾT THÚC

0
DrYodo