คำตอบที่ได้รับการยอมรับในขณะนี้เป็นคำตอบที่ดีที่สุด แต่ผมไม่คิดว่ามันไม่ได้งานที่ดีมากพอที่จะอธิบายว่าทำไม คำตอบอื่น ๆ นั้นดูสะอาดตากว่ามาก (ผู้ที่ต้องการเขียนคำแถลงกรณีที่น่าเกลียด) แต่มีแนวโน้มที่จะแย่ลงมากเมื่อคุณเริ่มใช้งานเครื่องชั่ง
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%
หากคุณดูที่แผนแบบสอบถามจะเห็นได้ชัดว่าทำไม - เพิ่มประเภท unpivot หรือรวม (หรือสวรรค์ห้าม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