我们正在编写要在客户服务器上运行的数据库升级脚本,该脚本可以是2012年以后的任何版本的SQL Server。
我们正在做的一件事是将DATETIME
列从本地时区格式迁移到UTC格式。
我编写了一个可以从迁移SQL调用的函数。
该函数使用2种方法之一,具体取决于SQL Server的版本-如果使用2016年或更高版本,则使用DATETIMEOFFSET
;如果使用旧版本,则使用后备。
问题在于,较旧的服务器不允许包含该函数,因为它包含DATETIMEOFFSET
关键字。
[我尝试将DATETIMEOFFSET
SQL移至字符串并使用sp_executesql
进行调用,但发现我无法从函数中调用存储过程。
关于如何处理此问题的任何想法?
我可以编写2个函数并根据服务器版本安装一个或另一个,但是不确定SQL Server数据工具和dacpacs是否可以实现。
这里是功能:
CREATE FUNCTION [dbo].[ConvertLocalDateToUtc]
(@LocalDate DATETIME2,
@LocalZone NVARCHAR(128))
RETURNS DATETIME2
AS
BEGIN
DECLARE @convertedDate DATETIME2;
IF (SELECT CAST(SERVERPROPERTY('ProductMajorVersion') AS INT)) >= 13
BEGIN
-- if SQL Server 2016 or later, this takes account of historical daylight saving times
DECLARE @ZonedLocalDate DATETIMEOFFSET = @LocalDate AT TIME ZONE @LocalZone;
DECLARE @ZonedUtcDate DATETIMEOFFSET = @ZonedLocalDate AT TIME ZONE 'UTC';
SET @convertedDate = CAST(@ZonedUtcDate AS DATETIME2);
END
ELSE
BEGIN
-- if earlier than SQL Server 2016 this uses the current time zone
-- which may or may not be the same DST as historical dates
SET @convertedDate = DATEADD(MI,(DATEDIFF(MI, SYSDATETIME(), SYSUTCDATETIME())), @LocalDate);
END
RETURN(@convertedDate);
END
我们设法通过以下部署后脚本对其进行修复。这与Martin Smith在评论中建议的解决方法类似。我们决定将这两个功能放在一个脚本中,而不是将一个基本功能和一个升级放在一个脚本中,以提高可维护性。
-- delete function if we already have it
IF object_id(N'ConvertLocalDateToUtc', N'FN') IS NOT NULL
DROP FUNCTION ConvertLocalDateToUtc
GO
DECLARE @SQLString nvarchar(MAX);
-- build server version specific function
-- if SQL Server 2016 or later, this takes account of historical daylight saving times
IF (SELECT CAST(SERVERPROPERTY('ProductMajorVersion') AS INT)) >= 13
BEGIN
SET @SQLString = N'
CREATE FUNCTION [dbo].[ConvertLocalDateToUtc]
(
@LocalDate DATETIME2,
@LocalZone NVARCHAR(128)
)
RETURNS DATETIME2
AS
BEGIN
DECLARE @convertedDate DATETIME2;
DECLARE @ZonedLocalDate DATETIMEOFFSET = @LocalDate AT TIME ZONE @LocalZone;
DECLARE @ZonedUtcDate DATETIMEOFFSET = @ZonedLocalDate AT TIME ZONE ''UTC'';
SET @convertedDate = CAST(@ZonedUtcDate AS DATETIME2);
RETURN(@convertedDate);
END
';
END
ELSE
BEGIN
-- if earlier than SQL Server 2016 this uses the current time zone
-- which may or may not be the same DST as historical dates
SET @SQLString = N'
CREATE FUNCTION [dbo].[ConvertLocalDateToUtc]
(
@LocalDate DATETIME2,
@LocalZone NVARCHAR(128)
)
RETURNS DATETIME2
AS
BEGIN
DECLARE @convertedDate DATETIME2;
SET @convertedDate = DATEADD(MI,(DATEDIFF(MI, SYSDATETIME(), SYSUTCDATETIME())), @LocalDate);
RETURN(@convertedDate);
END
';
END
-- run the sql to create the function
EXECUTE sp_executesql @SQLString;