На даний момент прийнята відповідь є найкращою відповіддю, але я не думаю, що це достатньо хороша робота з поясненням причини. Інші відповіді, безумовно, на перший погляд виглядають набагато чистішими (хто хоче написати цю потворну заяву), але, ймовірно, будуть набагато гіршими, коли ви почнете працювати в масштабі.
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 ),
DATEADD( DAY,
CASE WHEN RAND() > 0 THEN 1
ELSE -1 END * ROUND( RAND(), 0 ),
CURRENT_TIMESTAMP ),
DATEADD( DAY,
CASE WHEN RAND() > 0 THEN 1
ELSE -1 END * ROUND( RAND(), 0 ),
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%
Якщо ви подивитесь на плани запитів, стає досить очевидним, чому - додаючи будь-який тип нерозбірки або сукупності (або не дай бог STRING_SPLIT), ви отримаєте всілякі додаткові оператори, які вам не потрібні (і це змушує план йдіть паралельно, забираючи ресурси, які інші запити можуть захотіти). За контрактом, 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,
(SELECT
MAX(call_case)
FROM ( VALUES
(MAX(date1)),
(MAX(date2))
,(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, ',', date2, ',', date3), ',') x
group by call_case