我有一个CSV我正在导入我们的数据库。其中一个“列”包含应为INT的数据,但有些行的数字仅在BIGINT范围内(因为它们是来自我们的合作伙伴的测试数据)。我们在内部存储INT,不想改变。
我想安全地从BIGINT转发到INT。安全地,我的意思是如果发生算术溢出,则不应该引发错误。如果转换/转换成功,我希望我的脚本继续。如果它失败了,我希望它短路。我似乎无法弄清楚正确的语法。这就是我所拥有的:
DECLARE @UserIDBigInt BIGINT = 9723021913; -- actually provided by query param
--Setting within the INT range successfully converts
--SET @UserIDBigInt = 5;
DECLARE @UserID INT = CONVERT(INT, @UserIDBigInt);
--DECLARE @UserID INT = CAST(@UserIDBigInt AS INT);
SELECT @UserIDBigInt
SELECT @UserID
IF @UserID IS NOT NULL BEGIN
SELECT 'Handle it as reliable data'
END
我已经考虑将@UserIDBigInt与INT的有效范围(-2 ^ 31(-2,147,483,648)到2 ^ 31-1(2,147,483,647))进行比较,但我真的不喜欢这种方法。那是我的后备。我希望能使用一些语言结构或内置函数。如果我必须与有效范围进行比较,是否至少有一些内置常量(如C#的int.MinValue& int.MaxValue)?
编辑:纠正错字。
答案 0 :(得分:6)
将这些添加到您的脚本中:
SET ARITHABORT OFF;
SET ARITHIGNORE ON;
这会将任何溢出值转换为NULL。
此处有更多信息:http://msdn.microsoft.com/en-us/library/ms184341.aspx
答案 1 :(得分:4)
将bigint
投放到varbinary
,然后将下半部分存储到@UserID
并检查上半部分:
如果上半部分全部为0而下半部分表示非负值,则@UserID
包含正确的int
值;
如果上半部分全部为1而@UserID
为负,那也没关系;
否则会出现算术溢出。
这是一个实现:
DECLARE @UserIDBigInt BIGINT = 9723021913;
DECLARE @UserID INT, @HighInt INT;
WITH v AS (SELECT CAST(@UserIDBigInt AS varbinary) AS bin)
SELECT
@HighInt = SUBSTRING(bin, 1, 4),
@UserID = SUBSTRING(bin, 5, 4)
FROM v;
IF (@HighInt = 0 AND @UserID >= 0 OR @HighInt = -1 AND @UserID < 0) BEGIN
SELECT 'Handle it as reliable data'
END
答案 2 :(得分:1)
我不确定这是最好的答案,但这是我之前提出的。可以捕获异常/错误并优雅地继续执行。
示例:
DECLARE @UserIDBigInt BIGINT = 9723021913;
DECLARE @UserID INT;
BEGIN TRY
SET @UserID = @UserIDBigInt;
END TRY BEGIN CATCH
END CATCH
IF @UserID IS NULL BEGIN
SELECT 'Handle it as unreliable data'
RETURN
END
SELECT 'Handle it as reliable data'
答案 3 :(得分:0)
您还可以将值转换为字符串,将其修剪为长度并转换为int。不是最好的方法,但确保安全的简单方法