因此,我一直在为正在构建的SSRS报告处理许多存储过程,并且出现了一个奇怪的错误,需要一双新鲜的眼睛才能看到我可能会丢失的内容。
我的过程非常简单-SELECT
表中的各个列,JOIN
到INSERT
表中,#temp
的所有列表格以显示为我的报告中的明细行。
我的完整过程如下所示:
SELECT
正如我所说,这段代码一直存在一个奇怪的问题。在过去的两个星期中,所有测试用例都运行良好。我正在使用USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[rpt_select_ACHW_Ob]
@PR_ID INT
AS BEGIN
SET NOCOUNT ON;
CREATE TABLE #temp
(BuildingNum INT,
MTHD VARCHAR(50),
ObDescript NVARCHAR(50),
SizeRemarks VARCHAR(50),
ObLength NUMERIC,
ObWidth NUMERIC,
ObArea NUMERIC,
Stories NUMERIC,
Grade VARCHAR(50),
YearBuilt SMALLINT,
Condition VARCHAR(50),
Phys NUMERIC,
FC VARCHAR(50),
PercentDone NUMERIC,
TaxValue NUMERIC)
DECLARE @RowCounter INT, @h INT
SET @RowCounter = 11
INSERT INTO #temp(BuildingNum, MTHD, ObDescript, SizeRemarks, ObLength, ObWidth, ObArea, Stories, Grade, YearBuilt, Condition, Phys, FC, PercentDone, TaxValue)
SELECT ob.Ob_LineNumber AS BuildingNum,
CASE WHEN ob.SP IS NOT NULL THEN 'S' ELSE 'P' END AS MTHD,
som.Id AS ObDescript,
CASE WHEN ob.SF IS NULL THEN ob.CN ELSE CAST((ob.SF + '/' + ob.CN) AS VARCHAR) END AS SizeRemarks,
CASE WHEN ob.ob_Length IS NULL THEN 0 ELSE ob.Ob_Length END AS ObLength,
CASE WHEN ob.ob_Width IS NULL THEN 0 ELSE ob.Ob_Width END AS ObWidth,
CASE WHEN ob.ob_Length IS NULL WHEN ob.ob_Width IS NULL THEN 0 THEN 0 ELSE (ob.Ob_Length * ob.Ob_Width) END AS ObArea,
ob.Ob_NStories AS OBStories,
sovg.Grade AS ObGrade,
ob.Ob_YearBuilt As ObYearBuilt,
ob.Ob_ConditionCode AS ObConditionCode,
ob.DR AS phys,
ob.FC AS FC,
ob.Ob_PercentComplete AS ObPercentComplete,
ob.Ob_ValueTax AS TaxValue
FROM t_Ob ob WITH (NOLOCK)
LEFT JOIN t_ObToPR otpr WITH (NOLOCK) ON ob.Ob_ID=otpr.Ob_ID
LEFT JOIN t_PR pr WITH (NOLOCK) ON otpr.PR_ID=pr.PR_ID
LEFT JOIN t_S_Grade sovg WITH (NOLOCK) ON ob.S_Grade_ID=sovg.S_Grade_ID
LEFT JOIN t_SObD sod WITH (NOLOCK) ON ob.SObD_ID=sod.SObD_ID
LEFT JOIN t_SObM som WITH (NOLOCK) ON sod.SObM_ID=som.SObM_ID
WHERE pr.PR_Id = @PR_ID
SET @h = (SELECT COUNT(*) FROM #temp)
WHILE @h < @RowCounter OR @h % @RowCounter > 0
BEGIN
INSERT INTO #temp (BuildingNum) VALUES (NULL)
SET @h = @h + 1
END
SELECT * FROM #temp
ORDER BY CASE WHEN BuildingNum IS NULL THEN 1 ELSE 0 END, BuildingNum
END
根据参数EXEC
选择记录,并且工作正常。昨天,在未触及任何代码之后,我开始仅针对某些@PR_ID
值生成错误代码:
消息8114,级别16,状态5,过程rpt_select_ACHW_Ob,第28行[批处理开始第2行]
将数据类型varchar转换为数字时出错。
第28行将引导您转到PR_ID
,我已对其进行了10次检查。 FC VARCHAR(50)
表中声明的所有数据类型都与所选值完全匹配。是否有人对为什么它停止工作有任何想法?
Here's a dbFiddle link with some sample data
当前正在使用SQL Server 2012。
答案 0 :(得分:4)
这个评论太长了。
发生了两件事之一。不太可能是您的原始查询编写正确,并且有人更改了基础表(将整数列更改为字符串列),然后用非数字数据填充了字符串列。
更可能的情况是您的原始查询具有隐式转换。这只是一个等待发生的问题-现在您知道为什么了。您有一条来自SQL Server的错误消息,它没有指定发生问题的表,行或列。 Arrggg!
我的建议是遍历查询并检查每个表达式和比较,以确保类型兼容(数字/数字,字符串/字符串,日期时间/日期时间足够)。如果不是,请添加显式转换。您可以使用try_convert()
或try_cast()
添加转换,这至少会避免错误(以产生NULL
为代价)。
我希望SQL Server具有“无隐式转换”模式,在此模式下,它会警告您查询正在使用此类转换。 las,不。因此,养成编写查询的习惯,以便所有转换都是明确的。
编辑:
例如(基于注释),该表达式:
CAST((ob.SF + '/' + ob.CN) AS VARCHAR
应为:
CAST( (ob.SF as VARCHAR(255)) + '/' + ob.CN) AS VARCHAR(255))
请注意,您应该在SQL Server的所有CHAR()
/ VARCHAR()
引用中都包含长度。
答案 1 :(得分:1)
根据您对@Gordon的回答的评论:如果准确,则将Gordon的回答标记为您的解决方案。
这将失败:
Declare @SF Int = 12
Declare @CN VarChar(10) = '2'
Select CAST((@SF + '/' + @CN) AS VARCHAR)
除非您添加演员表:
Select CAST((Cast(@SF As VarChar(10)) + '/' + @CN) AS VARCHAR)
结果
12/2