SR0014:从 {Type1} 强制转换为 {Type2} 时可能会丢失数据

规则 ID

SR0014

类别

Microsoft.Design

是否重大更改

非重大更改

原因

列、变量或参数的数据类型正隐式转换到另一个数据类型。

规则说明

如果数据类型未一致地分配到列、变量、或参数,则它们会在包含这些对象的 Transact-SQL 代码运行时被隐式转换。 这种类型的转换不仅会降低性能,而且还在某些情况下导致细微的数据丢失。 例如,如果 WHERE 子句中的每一列都必须进行转换,则表扫描可以运行。 更糟糕的是,如果 Unicode 字符串转换为使用不同代码页的 ASCII 字符串,数据可能会丢失。

此规则不会:

  • 请检查计算所得的列的类型,因为该类型直到运行时才知道。

  • 分析 CASE 语句内的任何内容。 它也不会分析 CASE 语句的返回值。

  • 分析对 ISNULL 调用的输入参数或返回值

SQL CLR 对象

对于 SQL Server 公共语言运行时 (SQL CLR) 对象,应进行以下检查:

对象类型

验证类型兼容性

验证潜在数据丢失

Columns

存储过程和函数参数

变量

XML 类型

当将一个对象赋给另一个,并且两者都是 SQL CLR 对象类型时,它们必须是相同的类型或将生成一个警告。 您可以显式地只将下列转换为 SQL CLR 对象类型否则会出现警告:binary、varbinary、 char、nchar、varchar 或 nvarchar。

系统函数

将为以下系统函数检索返回类型: @@ERROR、@@FETCH_STATUS、 @@IDENTITY、@@ROWCOUNT、@@TRANCOUNT、 CHECKSUM、CHECKSUM_AGG、COUNT、 COUNT_BIG、GROUPING、STDEV、 STDEVP、VAR、ARP、 RANK、DENSE_RANK、NTILE、 ROW_NUMBER、CURSOR_STATUS、SYSDATETIME、SYSDATETIMEOFFSET、SYSUTCDATETIME、 DATEDIFF、DATENAME、DATEPART、 DAY、MONTH、YEAR、 CURRENT_TIMESTAMP、GETDATE、GETUTCDATE、AVG、SUM、MIN、MAX、DATEADD、SWITCHOFFSET、TODATETIMEOFFSET 和 ISNULL。

提示

不执行任何检查以确保在函数上下文中的输入有效,但 LEFT、 RIGHT、CONVERT 和 CAST 函数除外。 例如,没有出现 SUM(datetime2 类型)的警告,因为数据库代码分析不了解 SUM 函数期望什么类型的输入。 输入表达式本身如果存在问题则会出现警告,例如指定 SUM(金钱 + 实际)的问题。

正在执行的特定检查

下表描述了执行的特定的检查,带每个检查的示例:

语言构造

检查内容

示例

参数的默认值。

参数数据类型

CREATE PROCEDURE p1(
@p1 INT = 1)
AS
BEGIN
END

创建索引谓词

谓词是布尔值

CREATE INDEX index1 ON table1 (column1) 
WHERE column1 > 10

LEFT 或 RIGHT 函数的参数

字符串参数类型和长度

SET @v = LEFT('abc', 2)

CAST 和 CONVERT 函数的参数

表达式和类型有效

SET @v = CAST('abc' AS CHAR(10))

SET 语句

左侧和右侧具有兼容的类型

SET @v1 = 'xyz'
SELECT @v1 = c1 FROM t1

IF 语句谓词

谓词是布尔值

IF (@v > 10)

WHILE 语句谓词

谓词是布尔值

WHILE (@v > 10)

INSERT 语句

值和列正确

INSERT INTO t1(c1, c2) VALUES (99, 'xyz')
INSERT INTO t1 SELECT c1 FROM t2.
注意注意
不检验通配符。例如:INSERT INTO t1 SELECT * FROM t2

SELECT WHERE 谓词

谓词是布尔值

SELECT * FROM t1 WHERE c1 > 10

SELECT TOP 表达式

表达式为整数类型或 float 类型

SELECT TOP 4 * FROM t1 
SELECT TOP 1.5 PERCENT * FROM t1

UPDATE 语句

表达式和列有兼容的类型

UPDATE t1 SET c1 = 100

UPDATE 谓词

谓词是布尔值

UPDATE t1 SET c1 = 100 
WHERE c1 > 100

UPDATE TOP 表达式

表达式为整数类型或 float 类型

UPDATE TOP 4 table1

删除谓词

谓词是布尔值

DELETE t1 WHERE c1 > 10

删除 TOP 表达式

表达式为整数类型或 float 类型

DELETE TOP 2 FROM t1

DECLARE 变量声明

初始值和数据类型是兼容的

DECLARE @v INT = 10

执行声明参数和返回类型

形参和实参

CREATE PROCEDURE p1 (@p1 INT) AS
GO
EXECUTE p1 100
EXECUTE @v1 = p1 100

RETURN 语句

RETURN 表达式有兼容的数据类型

CREATE FUNCTION f1() RETURNS INT
AS
BEGIN
  RETURN 100
END

MERGE 语句条件

条件为布尔值

MERGE t1 USING t2
ON t1.c1 = t2.c2
WHEN t1.c1 > 10 THEN DELETE

如何解决冲突

您可以避免并解决这些问题,方法是不断指定数据类型并明确地在需要类型的地方转换它们。 有关如何指定显式转换数据类型的更多信息,请参见 Microsoft 网站的此页面:CAST and CONVERT (Transact-SQL)(CAST 和 CONVERT (Transact-SQL))。

何时禁止显示警告

不应禁止显示此类警告。

示例

此示例演示了两个存储过程,其将数据插入表格。 第一个过程 procWithWarning,将导致一个数据类型的隐式转换。 第二个过程 procFixed,显示了如何添加显式转换以最大化性能并保留所有数据。

CREATE TABLE [dbo].[Table2] 
( 
[ID] INT NOT NULL IDENTITY(0, 1), 
[c1] INT NOT NULL , 
[c2] INT NOT NULL , 
[c3] BIGINT NOT NULL , 
[Comment] VARCHAR (25)
)
ON [PRIMARY]

CREATE PROCEDURE [dbo].[procWithWarning]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(30)
) 
AS 
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment) 
VALUES (@Value1, @Value2, @Value3, @Comment) 

END

CREATE PROCEDURE [dbo].[procFixed]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(10)
) 
AS 
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment) 
VALUES (@Value1, @Value2, @Value3, CAST(@Comment AS VARCHAR(25))) 

END

请参见

概念

分析数据库代码以提高代码质量