Jawaban yang saat ini diterima adalah jawaban terbaik, tetapi saya pikir itu tidak cukup baik untuk menjelaskan alasannya. Sekilas jawaban lain tampak jauh lebih bersih (yang ingin menulis pernyataan kasus yang jelek), tetapi kemungkinan akan jauh lebih buruk ketika Anda mulai beroperasi pada skala.
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: )
Inilah cara saya mengatur semuanya
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;
Di sistem saya ini membuat saya 12.872.738 baris dalam tabel. Jika saya mencoba setiap pertanyaan di atas (tweaked toSELECT INTO
jadi saya tidak perlu menunggu sampai selesai mencetak hasil dalam SSMS), saya mendapatkan hasil berikut:
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%
Jika Anda melihat rencana kueri, menjadi sangat jelas mengapa - menambahkan segala jenis unpivot atau agregat (atau surga dilarang STRING_SPLIT
) Anda akan berakhir dengan semua jenis operator tambahan yang tidak Anda butuhkan (dan itu memaksa rencana untuk pergi paralel, mengambil sumber daya pertanyaan lain mungkin ingin). Dengan kontrak, CASE
solusi berbasis tidak berjalan paralel, berjalan sangat cepat, dan sangat sederhana.
Dalam hal ini, kecuali Anda memiliki sumber daya tidak terbatas (Anda tidak memiliki), Anda harus memilih pendekatan yang paling sederhana dan tercepat.
Ada pertanyaan tentang apa yang harus dilakukan jika Anda perlu terus menambahkan kolom baru dan memperluas pernyataan kasus. Ya, ini menjadi sulit, tetapi begitu juga setiap solusi lainnya. Jika ini sebenarnya alur kerja yang masuk akal, maka Anda harus mendesain ulang tabel Anda. Apa yang Anda inginkan mungkin terlihat seperti ini:
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;
Ini tentu saja tidak bebas dari masalah kinerja potensial, dan akan membutuhkan penyetelan indeks yang cermat, tetapi merupakan cara terbaik untuk menangani sejumlah cap waktu potensial yang sewenang-wenang
Jika ada jawaban yang dihapus, berikut adalah versi yang saya bandingkan (agar)
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