Các câu trả lời chấp nhận hiện nay là câu trả lời tốt nhất, nhưng tôi không nghĩ rằng nó làm một công việc tốt, đủ để giải thích tại sao. Các câu trả lời khác chắc chắn trông gọn gàng hơn trong nháy mắt (ai muốn viết tuyên bố trường hợp xấu xí đó), nhưng có khả năng tồi tệ hơn nhiều khi bạn bắt đầu hoạt động ở quy mô.
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: )
Đây là cách tôi thiết lập mọi thứ
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;
Trên hệ thống của tôi, điều này giúp tôi có 12.872.738 hàng trong bảng. Nếu tôi thử từng truy vấn ở trên (được điều chỉnh để SELECT INTO
tôi không cần đợi nó hoàn thành việc in kết quả trong SSMS), tôi sẽ nhận được kết quả sau:
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%
Nếu bạn nhìn vào các kế hoạch truy vấn, điều đó trở nên khá rõ ràng tại sao - thêm bất kỳ loại không liên kết hoặc tổng hợp nào (hoặc trời cấm STRING_SPLIT
) bạn sẽ kết thúc với tất cả các loại toán tử bổ sung mà bạn không cần (và nó buộc kế hoạch phải đi song song, lấy đi các tài nguyên mà các truy vấn khác có thể muốn). Theo hợp đồng, CASE
giải pháp dựa trên không đi song song, chạy rất nhanh và cực kỳ đơn giản.
Trong trường hợp này, trừ khi bạn có tài nguyên không giới hạn (bạn không), bạn nên chọn cách tiếp cận đơn giản và nhanh nhất.
Có một câu hỏi phải làm gì nếu bạn cần tiếp tục thêm các cột mới và mở rộng báo cáo trường hợp. Vâng, điều này trở nên khó sử dụng, nhưng mọi giải pháp khác cũng vậy. Nếu đây thực sự là một quy trình công việc hợp lý, thì bạn nên thiết kế lại bảng của mình. Những gì bạn muốn có thể trông giống như thế này:
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;
Điều này chắc chắn không có vấn đề về hiệu suất tiềm năng và sẽ yêu cầu điều chỉnh chỉ số cẩn thận, nhưng là cách tốt nhất để xử lý số lượng dấu thời gian tiềm năng tùy ý
Trong trường hợp bất kỳ câu trả lời nào bị xóa, đây là các phiên bản tôi đang so sánh (theo thứ tự)
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