Chèn ngày từ chuỗi: CAST vs CONVERT


7

Hãy xem xét hai cách sau đây để chuyển đổi chuỗi varchar datetime thành trường ngày:

SELECT convert(date, '2012-12-21 21:12:00', 20) -- Only date is needed
SELECT cast('2012-12-21 21:12:00' as date) -- Only date is needed

Cả hai trả về những gì tôi mong đợi: Ngày không bao gồm thời gian, dưới dạng kiểu dữ liệu ngày.

Câu hỏi của tôi là: Có bất kỳ pro và nhược điểm của việc làm một trong hai cách?


Câu hỏi này có thể được mở rộng thành "sự khác biệt giữa diễn viên và chuyển đổi là gì?" Và thực sự được trả lời tốt ở đây stackoverflow.com/questions/707335/t-sql-cast-versus-convert
jyao

Câu trả lời:


10

Câu trả lời (trước đây) được chấp nhận không chính xác vì nó là một bài kiểm tra tồi và sai lệch. Hai truy vấn được so sánh không làm điều tương tự do một lỗi đánh máy đơn giản khiến chúng không phải là một so sánh táo với táo. Các thử nghiệm trong câu trả lời được chấp nhận là thiên vị không công bằng ủng hộ CASThoạt động. Vấn đề là CONVERThoạt động đang được thực hiện với convert(date, GETDATE()+num,20)- một giá trị để chuyển đổi thay đổi trên mỗi hàng - trong khi CASTthao tác được thực hiện đơn giản cast(GETDATE() as date)- một giá trị để chuyển đổi phù hợp trên tất cả các hàng và được thay thế trong kế hoạch thực hiện như một hằng số. Và trên thực tế, nhìn vào kế hoạch thực hiện XML thậm chí còn cho thấy hoạt động thực tế được thực hiện như hiện tại CONVERT(date,getdate(),0)!!

Trong chừng mực mà thử nghiệm của tôi cho thấy (sau khi làm cho chúng bằng nhau thông qua việc sử dụng cast(GETDATE()+num as date)), thời gian thay đổi với chúng hầu như giống nhau (điều này có ý nghĩa nếu cả hai đều giảm xuống thành CONVERTdù sao) hoặc CONVERTchiến thắng:

SET STATISTICS IO, TIME ON;
    ;with t as (
               select convert(date, GETDATE(),20) as fecha , 0 as num
             union all
             select convert(date, GETDATE()+num,20) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

-- 4754-07-23
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 9031 ms,  elapsed time = 9377 ms.



-- VS    

SET STATISTICS IO, TIME ON;
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE() as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

--2016-08-26
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 8969 ms,  elapsed time = 9302 ms.




SET STATISTICS IO, TIME ON;
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE()+num as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

-- 4754-07-23
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 9438 ms,  elapsed time = 9878 ms.

Sự khác biệt chính giữa CAST và CONVERTCONVERTcho phép "kiểu" được chỉ định. "Kiểu" không chỉ cho phép điều chỉnh đầu ra khi chuyển đổi một chuỗi không thành chuỗi, mà còn cho phép chỉ định định dạng đầu vào khi chuyển đổi một chuỗi thành một chuỗi không:

SELECT CONVERT(DATE, '5/10/2016', 101); -- 101 = mm/dd/yyyy
-- 2016-05-10


SELECT CONVERT(DATE, '5/10/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-10-05

Bây giờ so sánh chức năng đó với CAST:

SELECT CAST('13/5/2016' AS DATE);
-- Msg 241, Level 16, State 1, Line 71
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 101); -- 101 = mm/dd/yyyy
-- Msg 241, Level 16, State 1, Line 76
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-05-13

Một điều nữa cần đề cập đến CAST: bởi vì nó không có tham số "kiểu", định dạng của chuỗi ngày được truyền vào được coi là của văn hóa hiện tại (thuộc tính phiên). Văn hóa hiện tại được biểu thị bởi các biến @@LANGID@@LANGUAGEhệ thống. Điều này có nghĩa là CASTtuyên bố thất bại trong bài kiểm tra trực tiếp ở trên có thể thành công cho một nền văn hóa / ngôn ngữ khác. Các thử nghiệm sau đây cho thấy hành vi này và cách chuỗi ngày tương tự hoạt động CASTkhi ngôn ngữ hiện tại là "tiếng Pháp" (và sẽ hoạt động với một số ngôn ngữ khác, dựa trên các giá trị trong dateformatcột trong sys.syslanguages):

IF (@@LANGID <> 0) -- us_english
BEGIN
    PRINT 'Changing LANGUAGE to English...';
    SET LANGUAGE ENGLISH;
    SELECT @@LANGUAGE AS [CurrentLanguage], @@LANGID AS [LangID];
END;

SELECT @@LANGUAGE, CAST('13/5/2016' AS DATE) AS [Test 1];
-- Msg 241, Level 16, State 1, Line 71
-- Conversion failed when converting date and/or time from character string.
GO

SELECT @@LANGUAGE, CONVERT(DATE, '13/5/2016', 103) AS [Test 2]; -- 103 = dd/mm/yyyy
-- us_english   2016-05-13
GO


IF (@@LANGID <> 2) -- Français
BEGIN
    PRINT 'Changing LANGUAGE to French...';
    SET LANGUAGE FRENCH;
    SELECT @@LANGUAGE AS [CurrentLanguage], @@LANGID AS [LangID];
END;

SELECT @@LANGUAGE, CAST('13/5/2016' AS DATE) AS [Test 3];
-- 2016-05-13
GO

SELECT @@LANGUAGE, CONVERT(DATE, '13/5/2016', 103) AS [Test 4]; -- 103 = dd/mm/yyyy
-- Français 2016-05-13
GO


-- Reset current language, if necessary.
IF (@@LANGID <> @@DEFAULT_LANGID)
BEGIN
    DECLARE @Language sysname;

    SELECT @Language = sl.[alias]
    FROM   sys.syslanguages sl
    WHERE  sl.[langid] = @@DEFAULT_LANGID;

    PRINT N'Changing LANGUAGE back to default: ' + @Language + N'...';

    SET LANGUAGE @Language;
    SELECT @@LANGUAGE AS [CurrentLanguage], @@LANGID AS [LangID];
END;

1
Quá hạn dài, nhưng cảm ơn rất nhiều vì thời gian của bạn cung cấp câu trả lời thấu đáo này. Tôi chỉ xem lại ngày hôm nay để viết một thủ tục cửa hàng và câu trả lời của bạn đã giúp rất nhiều! Cảm ơn một lần nữa!
pmdci

4

Tôi không nhận thấy bất kỳ sự khác biệt "hiệu suất" giữa hai. Rõ ràng "CHUYỂN ĐỔI" là Máy chủ Sql cụ thể trong khi CAST là tiêu chuẩn ANSI. Tôi tin CONVERT cung cấp cho bạn nhiều lựa chọn hơn. Bạn có thể xem các ưu / nhược điểm khác tại đây ( http://searchsqlserver.techtarget.com/tip/The-difference-b between-CAVERT-and-CAST-in-MySQL- Server )

Báo giá trực tiếp từ liên kết ...

Vì SQL Server cung cấp cả hai chức năng, có thể có một số nhầm lẫn về việc sử dụng tốt nhất và trong hoàn cảnh nào.

CONVERT dành riêng cho SQL Server và cho phép độ linh hoạt cao hơn khi chuyển đổi giữa các giá trị ngày và thời gian, số phân số và ký hiệu tiền tệ.

CAST là tiêu chuẩn ANSI hơn của hai chức năng, nghĩa là trong khi nó dễ mang theo hơn (nghĩa là một chức năng sử dụng CAST có thể được sử dụng trong các ứng dụng cơ sở dữ liệu khác ít nhiều), nó cũng ít mạnh hơn.


2
Vì các đầu vào không phải là các biến / cột datetime mà là các chuỗi varchar, nên tôi sử dụng CONVERT()để đảm bảo rằng kiểu 20 được sử dụng. CAST(string AS DATE)có thể phụ thuộc vào các cài đặt ngôn ngữ / kết nối ngôn ngữ / cơ sở dữ liệu / ngôn ngữ khác nhau.
ypercubeᵀᴹ

@ ypercubeᵀᴹ và Scott: có, CASTphụ thuộc vào thuộc tính LANGUAGEphiên. Tôi chỉ thêm một phần (bên dưới dòng) vào câu trả lời của tôi minh họa điều này.
Solomon Rutzky

3

Tôi đã thử so sánh ngớ ngẩn này. Đã chỉnh sửa, có một lỗi đánh máy mà @srutzky đưa ra. Kết quả gần đúng.

    ;with t as (
               select convert(date, GETDATE(),20) as fecha , 0 as num
             union all
             select convert(date, GETDATE()+num,20) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);

-- VS    
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE()+num as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);

Kết quả rất phù hợp:

  • Chuyển đổi: 8,6 giây
  • Diễn viên: 8,7 giây

Bạn đang chuyển đổi giá trị datetime, không phải varchar (như câu hỏi).
ypercubeᵀᴹ

1
@ypercube - Tôi bị thu hút bởi ví dụ của bạn và muốn chơi nhiều hơn một chút. Tôi đã sử dụng ví dụ ban đầu của bạn như đã thấy CAST dường như là người chiến thắng rõ ràng. Sau đó tôi đã sửa đổi ví dụ của bạn thành GetDate () thành một biến và sau đó sử dụng nó qua ví dụ của bạn. Kết quả của tôi không nhất quán và trong một vài trường hợp, CHUYỂN ĐỔI đến nhanh hơn - tôi đang cố gắng tìm hiểu tại sao lại như vậy.
Scott Hodgin

1
@srutzky Bạn nói đúng. Đã chỉnh sửa và lặp lại thử nghiệm.
vercelli

1
@srutzky Bạn không quá quan trọng! Tôi rất trân trọng điều này. (+1)
vercelli

1
@vercelli Vui mừng vì nó đã không đi sai đường. Các tin nhắn bằng văn bản thường xuất hiện dưới dạng snide / caustic, vì vậy tôi muốn làm rõ rằng tôi không phủ nhận về bạn :).
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.