从多个列获取最后日期

这感觉应该很简单。如何获取不同列中的最新日期

DROP TABLE #indebtedness
CREATE TABLE #indebtedness (call_case CHAR(10),date1 DATETIME,date2 DATETIME,date3 DATETIME)
INSERT #indebtedness VALUES ('Key1','2019-10-30','2019-11-30','2019-10-25')
INSERT #indebtedness VALUES ('Key2','2019-10-20','2019-10-15')
INSERT #indebtedness VALUES ('Key3','2019-11-11','2019-10-29','2019-10-30')
INSERT #indebtedness VALUES ('Key4',null,'2019-10-13')

select call_case,?? AS 'Latest Date' from #indebtedness 

我希望结果是:

call_case   Latest Date
Key1        2019-11-30 
Key2        2019-10-30 
Key3        2019-11-11 
Key4        2019-10-29 
ynn0705 回答:从多个列获取最后日期

使用CASE表达式:

SELECT
    call_case,CASE WHEN date1 > date2 AND date1 > date3
         THEN date1
         WHEN date2 > date3
         THEN date2
         ELSE date3 END AS [Latest Date]
FROM #indebtedness;

Demo

请注意,某些数据库(例如MySQL,SQL Server和SQLite)支持标量最大功能。 SQL Server没有,所以我们可以使用CASE表达式作为解决方法。

编辑:

看来,在您的实际表中,三个日期列中的一个或多个可能具有NULL值。我们可以对上述查询进行如下修改:

SELECT
    call_case,CASE WHEN (date1 > date2 OR date2 IS NULL) AND (date1 > date3 OR date3 IS NULL)
         THEN date1
         WHEN date2 > date3 OR date3 IS NULL
         THEN date2
         ELSE date3 END AS [Latest Date]
FROM #indebtedness;

Demo

,

尝试一下:

SELECT call_case,(SELECT
     MAX(call_case) 
   FROM ( VALUES 
            (MAX(date1)),(MAX(date2)),(max(date3)) 
        ) MyAlias(call_case)
  ) 
FROM #indebtedness
group by call_case
,

currently accepted answer是最好的答案,但我认为它不能很好地解释原因。其他答案一目了然(他们想写丑陋的case语句)看上去更干净,但是当您开始大规模运行时,答案可能会更糟。

SELECT @@VERSION

Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64) 
Mar 18 2018 09:11:49 
Copyright (c) Microsoft Corporation
Developer Edition (64-bit) on Windows 10 Enterprise 10.0 <X64> (Build 17763: )

这是我设置所有内容的方式

DECLARE @Offset bigint = 0;
DECLARE @Max bigint = 10000000;

DROP TABLE IF EXISTS #Indebtedness;
CREATE TABLE #Indebtedness
(
  call_case char(10) COLLATE DATABASE_DEFAULT NOT NULL,date1     datetime NULL,date2     datetime NULL,date3     datetime NULL
);

WHILE @Offset < @Max
BEGIN

  INSERT INTO #Indebtedness
  ( call_case,date1,date2,date3 )
    SELECT @Offset + ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL )),DATEADD( DAY,CASE WHEN RAND() > 0 THEN 1
                         ELSE -1 END * ROUND( RAND(),0 ),CURRENT_TIMESTAMP ),CURRENT_TIMESTAMP )
      FROM master.dbo.spt_values a
        CROSS APPLY master.dbo.spt_values b;


  SET @Offset = @Offset + ROWCOUNT_BIG();
END;

在我的系统上,这使我在表格中得到12,872,738行。如果我尝试上述每个查询(已调整为SELECT INTO,因此无需等待它完成在SSMS中的打印结果),我将得到以下结果:

Method                                | CPU time (ms) | Elapsed time (ms) | Relative Cost
-----------------------------------------------------------------------------------------
Tim Biegeleisen (CASE)                | 13485         | 2167              | 2%
Red Devil (Subquery over MAX columns) | 55187         | 9891              | 14%
Vignesh Kumar (Subquery over columns) | 33750         | 5139              | 5%
Serkan Arslan (UNPIVOT)               | 86205         | 15023             | 12%
Metal (STRING_SPLIT)                  | 459668        | 186742            | 68%

如果您查看查询计划,原因很明显-添加任何种类的unpivot或aggregate(或天堂禁止STRING_SPLIT),您将得到各种各样您不想要的其他运算符需求(这迫使计划并行进行,从而占用了其他查询可能想要的资源)。根据合同,基于CASE的解决方案不会并行运行,运行速度非常快,而且非常简单。

在这种情况下,除非您拥有无限资源(没有),否则应该选择最简单,最快的方法。


有一个问题,如果您需要继续添加新列并扩展case语句,该怎么办。是的,这很难处理,其他所有解决方案也是如此。如果这实际上是一个合理的工作流程,则应重新设计表格。您想要的可能看起来像这样:

CREATE TABLE #Indebtedness2
(
  call_case     char(10) COLLATE DATABASE_DEFAULT NOT NULL,activity_type bigint   NOT NULL,-- This indicates which date# column it was,if you care
  timestamp     datetime NOT NULL
);

SELECT Indebtedness.call_case,Indebtedness.activity_type,Indebtedness.timestamp
  FROM ( SELECT call_case,activity_type,timestamp,ROW_NUMBER() OVER ( PARTITION BY call_case
                                    ORDER BY timestamp DESC ) RowNumber
           FROM #Indebtedness2 ) Indebtedness
  WHERE Indebtedness.RowNumber = 1;

这当然不是没有潜在的性能问题,并且需要进行仔细的索引调整,但这是处理任意数量的潜在时间戳的最佳方法


万一答案被删除,这是我正在比较的版本(按顺序)

SELECT
    call_case,CASE WHEN date1 > date2 AND date1 > date3
         THEN date1
         WHEN date2 > date3
         THEN date2
         ELSE date3 END AS [Latest Date]
FROM #indebtedness;

SELECT call_case,(SELECT Max(v) 
   FROM (VALUES (date1),(date2),(date3),...) AS value(v)) as [MostRecentDate]
FROM #indebtedness

SELECT call_case,(max(date3)) 
        ) MyAlias(call_case)
  ) 
FROM #indebtedness
group by call_case

select call_case,MAX(date)  [Latest Date] from #indebtedness 
UNPIVOT(date FOR col IN ([date1],[date2],[date3])) UNPVT
GROUP BY call_case

select call_case,max(cast(x.Item as date)) as 'Latest Date' from #indebtedness  t
cross apply dbo.SplitString(concat(date1,',date3),') x
group by call_case
,

SQL FIDDLE

使用MAX()

SELECT call_case,...) AS value(v)) as [MostRecentDate]
FROM #indebtedness

使用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
 FROM  #indebtedness
,

在我看来,Pivot是此查询的最佳和高效选择。在MS SQL SERVER中复制并粘贴。请检查以下代码:

CREATE TABLE #indebtedness (call_case CHAR(10),date1 DATETIME,date2 DATETIME,date3 DATETIME)
INSERT #indebtedness VALUES ('Key1','2019-10-30','2019-11-30','2019-10-31')
INSERT #indebtedness VALUES ('Key2','2019-10-20','2019-11-21')
INSERT #indebtedness VALUES ('Key3','2019-11-11','2019-10-29','2019-10-30')
INSERT #indebtedness VALUES ('Key4',Null,'2019-10-13')

--Solution-1:
SELECT        
    call_case,MAX(RecnetDate) as MaxDateColumn         
FROM #indebtedness
UNPIVOT
(RecnetDate FOR COL IN ([date1],[date3])) as TRANSPOSE
GROUP BY call_case 

--Solution-2:
select 
    call_case,case 
    when date1>date2 and date1 > date3 then date1
    when date2>date3                   then date2
    when date3>date1                   then date1 
   else date3 end as date
from #indebtedness as a 


Drop table #indebtedness
,

正如其他人指出的那样,这实际上应该在设计级别进行重新评估。下面是使用两个表的不同设计的示例,以更好地完成您要在结果中寻找的外观。这将使增长更加有利。

这里是一个示例(使用了不同的表名):

-- Drop pre-existing tables
DROP TABLE #call_log
DROP TABLE #case_type

-- Create table for Case Types
CREATE TABLE #case_type (id INT PRIMARY KEY CLUSTERED NOT NULL,descript VARCHAR(50) NOT NULL)
INSERT #case_type VALUES (1,'No Answer')
INSERT #case_type VALUES (2,'Answer')
INSERT #case_type VALUES (3,'Not Exist')
INSERT #case_type VALUES (4,'whatsapp')
INSERT #case_type VALUES (5,'autodial')
INSERT #case_type VALUES (6,'SMS')

-- Create a Call Log table with a primary identity key and also an index on the call types
CREATE TABLE #call_log (call_num BIGINT PRIMARY KEY CLUSTERED IDENTITY NOT NULL,call_type INT NOT NULL REFERENCES #case_type(id),call_date DATETIME)
CREATE NONCLUSTERED INDEX ix_call_log_entry_type ON #call_log(call_type)
INSERT #call_log(call_type,call_date) VALUES (1,'2019-11-30')
INSERT #call_log(call_type,call_date) VALUES (2,'2019-10-15')
INSERT #call_log(call_type,call_date) VALUES (3,null)
INSERT #call_log(call_type,'2019-10-29')
INSERT #call_log(call_type,'2019-10-25')
INSERT #call_log(call_type,'2019-10-30')
INSERT #call_log(call_type,'2019-10-13')
INSERT #call_log(call_type,'2019-10-20')
INSERT #call_log(call_type,'2019-10-30')

-- use an aggregate to show only the latest date for each case type
SELECT DISTINCT ct.descript,MAX(cl.call_date) AS "Date" 
    FROM #call_log cl JOIN #case_type ct ON cl.call_type = ct.id GROUP BY ct.descript

这允许添加更多案例类型,添加更多日志条目,并提供更好的设计。

这只是出于学习目的的示例。

本文链接:https://www.f2er.com/3154392.html

大家都在问