Birden fazla sütun SQL MAX?


372

Birden fazla sütunun en fazla satır başına 1 değerini nasıl döndürürsünüz:

Tablo ismi

[Number, Date1, Date2, Date3, Cost]

Ben böyle bir şey dönmek gerekir:

[Number, Most_Recent_Date, Cost]

Sorgu?

Yanıtlar:


161

CASE deyimini kullanabilirsiniz:

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 ve üstü için Sven'in daha basit cevabını aşağıda düşünebilirsiniz.]


11
Kullanmak yeterli olmaz WHEN Date1 > Date2 AND Date1 > Date3 THEN Date1; WHEN Date2 > Date3 THEN Date3; ELSE Date3mı?
Treb

21
Açık cevap, ancak NULL değerleri ile çalışmıyor ve bunu düzeltmeye çalışmak çok dağınık hale geliyor.
hayal kırıklığına uğradı

5
Bu eski gönderiyi necroing, ancak her tarihi NULL'ları işlemek için bir COALESCE içine sarın. O zaman WHEN ifadelerinden biri şöyle görünecektir: WHEN Tarih1> = COALESCE (Tarih2, '') VE Tarih1> = COALESCE (Tarih3, '') SONRA Tarih3 (diğeri için aynısını yapın)
Bill Sambrone

Buraya MySQL yolu arayanlar için @ bajafresh4life yanıtına bir göz atın: stackoverflow.com/a/331873/1412157
LucaM

2
BTW, Date3> Date1 olsa bile Date2 boş olduğunda Date1 değerini döndürür.
jumxozizi

853

İşte MaxT-SQL ve SQL Server kullanarak işlevsellik için güzel bir çözüm

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

47
SQL sürümü> = 2008 olmalıdır.
Daniel

10
Bu 2008 ile çok iyi çalışır ve NULL'ları işler. Çok güzel bir çözüm.
nycdan

10
@Cheburek: (v) değerinden, "değer" sanal tablonun diğer adıdır ve "v" tarih değerlerinin sanal sütununun adıdır.
Jonas Lincoln

2
Bu harika. Bu Value () sanal tablosunun belgelerini nerede bulabilirim?
My Other Me

33
Başlangıçta VALUE (v) 'i de anlamadım. VALUE değerini anlamak istiyorsanız, sanal 1 sütun tablosu oluşturan bu sorguyu deneyin: SELECT * FROM (VALUES (1), (5), (1)) olarak listOfValues ​​(columnName) ve sanal 2 sütun tablosu oluşturan bu sorgu: SELECT * FROM (DEĞERLER (1,2), (5,3), (1,4)) tableOfValues ​​(columnName1, ColumnName2) olarak Artık bu örnek sorgunun neden AS değeri (v) olduğunu anlayabilirsiniz. Son sorgum şuna benzer: SELECT Max (currentValues) olarak Max FROM (VALUES (12), (25), (35)) AS allCurrents (currentValues) Bu durumda 35 olan maksimum değeri seçecektir.
Jackson

148

MySQL kullanıyorsanız,

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

41
tag sqlserver olduğunu
Codewerks

104
Doğru, ancak insanlar bu soruyu MySQL ile ilgili olarak bulduklarında hala çok yararlı bir cevap.
philfreo

4
PostgreSQL da mevcuttur 8.1 .
Donmuş Alev

4
NULL ile iyi başa çıkmaz, ancak sütun değerlerinizin etrafında birleşirseniz (sütun1, 0) gazla
Stan Quinn

Ve bu çözüm ne olacak: stackoverflow.com/a/2166693/4824854
Sandburg

64

UNPIVOT(1) 'in açık ara en hızlı olduğu 3 yöntem daha var , ardından (1)' den çok daha yavaş ancak (2) 'den daha hızlı olan Simüle Unpivot (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

Çözüm 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

Çözüm 2 (Satır başına alt sorgu)

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

Çözüm 3 (Simüle Edilmiş 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
Güzel. PIVOT ve UNPIVOT operatörlerinin farkında değildim.
Sako73

SQL Server'ın hangi sürümlerinin pivot / unpivot'u desteklediğini biliyor musunuz?
hayal kırıklığına uğradı

1
@CraigYoung SQL Server 2005 ve COMPATIBILITY_LEVEL 90 olarak ayarlandı.
Paul Syfrett

18

Aşağıdaki iki örnekten biri çalışacaktır:

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

İkincisi lassevk'in cevabına bir eklentidir .

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 

İlk cevap iyidir, ancak önemli ölçüde basitleştirilebilir. İkinci cevap NULL değerleri ile çalışmaz. Bu sorunu çözmeye çalışmak çok dağınık oluyor.
hayal kırıklığına uğradı

Gereksiz bir zımni DISTINCT işleminden kaçınmak için UNION TÜMÜ'nü kullanmalısınız.
JamieSee

17

T-SQL için (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

Benim için herhangi bir SQL sürümünde çalıştı, güzel bir çözüm
Kirill

9

Skaler İşlev her türlü performans sorununa neden olur, bu nedenle mantığı mümkünse Satır İçi Tablo Değerli İşlevine sarmak daha iyidir. Bu, en fazla on tarih listesinden Min / Maks tarihleri ​​seçen bazı Kullanıcı Tanımlı İşlevleri değiştirmek için kullandığım işlevdir. 1 Milyon satırlık veri kümemde test edildiğimde, Skaler Fonksiyonu sorguyu öldürmeden önce 15 dakikadan fazla sürdü, Inline TVF, 1 dakika sürdü ve sonuç kümesini geçici bir tabloya seçmekle aynı süreydi. Bunu kullanmak için SELECT (SEÇ) veya CROSS UYGULAMASI altındaki bir alt sorgudan işlevi çağırın.

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 

Bu durumun yazılması biraz daha kolaydır ve vaka ifadesi sırayla değerlendirilirken değerlendirme adımlarını atlar.


4
Dikkatli. Tarih2 NULL ise, cevap Tarih3 olacaktır; Date1 daha büyük olsa bile.
hayal kırıklığına uğradı

4

Ne yazık ki Lasse'nin cevabı , görünüşte açık olsa da, çok önemli bir kusura sahip. NULL değerleri işleyemez. Tek bir NULL değeri Date1 döndürülür. Ne yazık ki bu sorunu çözmek için yapılan herhangi bir girişim son derece dağınık olma eğilimindedir ve 4 veya daha fazla değere çok iyi ölçeklenmez.

databyss'ın ilk cevabı iyi görünüyordu (ve iyi). Ancak, cevabın tek bir tablodan daha basit 3 değerler yerine çok masalı birleştirmeden 3 değere kolayca tahmin edilip edilmeyeceği açık değildi. Sadece en fazla 3 sütun almak için bir alt sorguya böyle bir sorgu açmaktan kaçınmak istedim, aynı zamanda databyss mükemmel fikir biraz temizlenebilir eminim.

Daha fazla uzatmadan, benim çözümüm (veritabanlarının fikrinden türetilmiş).
Çok masalı birleştirmenin etkisini simüle etmek için sabit birleşimleri seçerek sabitleri kullanır. Dikkat edilmesi gereken önemli olan, tüm gerekli takma adların doğru bir şekilde taşınmasıdır (her zaman böyle değildir) ve bu, kalıbı ek sütunlarla oldukça basit ve oldukça ölçeklenebilir tutar.

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

Sorun: Bir işletmeye verilen minimum ücret değerini seçin Gereksinimler: Ajans ücretleri boş olabilir

[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 

Esinlenen bu cevap dan Nat


3

SQL Server 2005 kullanıyorsanız, UNPIVOT özelliğini kullanabilirsiniz. İşte tam bir örnek:

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
Sanırım sendika örneğini daha çok seviyorum.
Lance Fisher

"En fazla birkaç sütunun SATIR BAŞINA BİR DEĞERİ nasıl döndürürsünüz?"
Niikola

3

ÇAPRAZ UYGULAYI Kullanma (2005+ için) ....

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

3

SQL Server 2012'den IIF kullanabiliriz .

 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

Oldukça güzel, ama null'larla başa çıkmıyor. Örneğin:DECLARE @Date1 DATE='2014-08-01'; DECLARE @Date2 DATE=null; DECLARE @Date3 DATE='2014-07-05'; /*this gets returned*/
jumxozizi

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
Null'ları

1

Lütfen kullanmayı deneyin UNPIVOT:

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

1

Ben duruma göre çözümleri tercih ederim, benim varsayım, çapraz uygulama, değerler (), özel işlevler vb.

Aşağıda, olası test durumlarının çoğuyla null değerleri işleyen case-when sürümü verilmiştir:

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
;

ve sonuç:

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
Tanrım, teşekkürler efendim! Bana hala null veren bir canavar formülünün bu halini yapmak için çok zaman harcadım ve şimdi tünelin sonunda ışığı görüyorum.
Max

0

Tarihleri ​​ilettiğiniz bir işlevi oluşturabilir ve sonra işlevi aşağıdaki gibi select deyimine ekleyebilirsiniz. Sayı, dbo.fxMost_Recent_Date (Tarih1, Tarih2, Tarih3), Maliyet'i seçin

create FUNCTION  fxMost_Recent_Date 

(@ Tarih1 smalldatetime, @ Tarih2 smalldatetime, @ Tarih3 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

SON



0

DURUMDA KULLANMAK için başka bir yol

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

resim açıklamasını buraya girinYukarıdaki tablo, maaş1, maaş2, maaş3, maaş4 sütunları olan bir çalışan maaş tablosudur.Aşağıdaki sorgu, dört sütundan maksimum değeri döndürür

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

Sorgunun üstünde çalıştırıldığında çıktı en büyük_değer (10001) olarak verilir

Yukarıdaki sorgu mantığı aşağıdaki gibidir:

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

çıktı 10001 olacak


Bu, sven tarafından 29 Temmuz '11'de yayınlanan çözümün neredeyse bir kopyası
Luuk

-3

İşte iyi bir çözüm:

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, vb olup olmadığını bilmiyorum ... M $ ACCESS yardım üzerinde bir fonksiyon var MAXA(Value1;Value2;...) böyle yapması gerekiyordu .

Umut birine yardım edebilir.

PD: Değerler sütunlar veya hesaplananlar vb. Olabilir.


1
Microsoft Access tamamen farklı bir üründür. Ayrıca, böyle bir işlevle ilgili iddianızı kaynaklayabilir misiniz? Bunu Access'te hiç görmedim veya duymadım.
deutschZuid

1
MAXAAccess değil bir Excel işlevidir .
Felix Eve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.