转换数据类型varchar时出错

时间:2009-08-06 09:09:44

标签: sql sql-server tsql

我目前有一个列为varchar的表格。此列可以包含数字或文本。在某些查询中,我将其视为bigint列(我在其与bigint的另一个表中的列之间进行连接)

只要这个字段中只有数字没有问题,但是在这个字段中,即使一行中有文本而不是数字,我得到了“将数据类型varchar转换为bigint时出错”。 “错误,即使在WHERE部分我确定没有文本字段出现。

为了解决这个问题,我创建了一个视图如下:

SELECT     TOP (100) PERCENT ID, CAST(MyCol AS bigint) AS MyCol
FROM         MyTable
WHERE     (isnumeric(MyCol) = 1)

但是,即使视图仅显示具有数值的行并将Mycol强制转换为bigint,但在运行以下查询时,仍会出现错误,将数据类型varchar转换为bigint

SELECT * FROM MyView where mycol=1

在对视图进行查询时,它不应该知道它背后发生了什么!它应该只是看到两个bigint领域! (see attached image,甚至mssql管理工作室都将视图字段显示为bigint)

8 个答案:

答案 0 :(得分:2)

行。我终于创建了一个有效的视图:

SELECT TOP (100) PERCENT id, CAST(CASE WHEN IsNumeric(MyCol) = 1 THEN MyCol ELSE NULL END AS bigint) AS MyCol
FROM         dbo.MyTable
WHERE     (MyCol NOT LIKE '%[^0-9]%')

感谢 AdaTheDev CodeByMoonlight 。我用你的两个答案来解决这个问题。 (当然也要感谢其他回复者)

现在,当我与其他bigint cols连接或执行类似'SELECT * FROM MyView where mycol = 1'之类的操作时,它会返回正确的结果且没有错误。我的猜测是查询中的CAST本身会导致查询优化器不查看原始表格,正如Christian Hayter所说的可能会继续其他视图

答案 1 :(得分:1)

理想情况下,您希望尽量避免以这种形式存储数据 - 将BIGINT数据拆分为单独的列,以获得性能和易于查询。

但是,您可以像这个例子一样进行JOIN。注意,我没有使用ISNUMERIC()来确定它是否是有效的BIGINT,因为这会验证会导致转换错误的错误值(例如十进制数)。

DECLARE @MyTable TABLE (MyCol VARCHAR(20))
DECLARE @OtherTable TABLE (Id BIGINT)

INSERT @MyTable VALUES ('1')
INSERT @MyTable VALUES ('Text')
INSERT @MyTable VALUES ('1 and some text')
INSERT @MyTable VALUES ('1.34')
INSERT @MyTable VALUES ('2')
INSERT @OtherTable VALUES (1)
INSERT @OtherTable VALUES (2)
INSERT @OtherTable VALUES (3)

SELECT *
FROM @MyTable m
    JOIN @OtherTable o ON CAST(m.MyCol AS BIGINT) = o.Id
WHERE m.MyCol NOT LIKE '%[^0-9]%'

<强>更新 我可以找到使用它来为特定整数值设置WHERE子句而不在where子句中所谓的bigint列上执行另一个CAST()的唯一方法是使用用户定义的函数:

CREATE  FUNCTION [dbo].[fnBigIntRecordsOnly]()
RETURNS @Results TABLE (BigIntCol BIGINT)
AS
BEGIN
INSERT @Results
SELECT CAST(MyCol AS BIGINT)
FROM MyTable
WHERE MyCol NOT LIKE '%[^0-9]%'
RETURN
END

SELECT * FROM [dbo].[fnBigIntRecordsOnly]() WHERE BigIntCol = 1

我认为这不是一个明智的表现,但它是一个解决方案

答案 2 :(得分:1)

回答有关错误消息的问题:当您在另一个查询中引用视图名称时(假设它是传统视图而非物化视图),SQL Server有效地将视图定义宏替换为消费查询,然后执行。

这样做的好处是查询优化器可以在看到整个查询时做得更好,而不是将视图单独优化为“黑盒子”。

结果是,如果发生错误,错误描述可能看起来很混乱,因为执行引擎正在访问数据的基础表,而不是视图。

我不确定如何处理物化视图,但我认为它们被视为表,因为视图数据被缓存在数据库中。

话虽如此,我同意以前的答案 - 你应该重新考虑你的表格设计,并将文本和整数数据值分成不同的列。

答案 3 :(得分:1)

尝试将您的观点更改为:

SELECT TOP 100 PERCENT ID, 
Cast(Case When IsNumeric(MyCol) = 1 Then MyCol Else null End AS bigint) AS MyCol
FROM MyTable
WHERE (IsNumeric(MyCol) = 1)

答案 4 :(得分:0)

您是否尝试将其他表格的bigint字段转换为varchar?至于我,执行更强大的转换是有意义的......如果varchar字段被索引,它不应该太大地影响你的性能。

答案 5 :(得分:0)

考虑创建一个冗余的bigint字段来保存af MyCol的整数值。

然后,您可以将新字段编入索引以加快连接速度。

答案 6 :(得分:0)

尝试分两个阶段进行选择。

首先创建一个视图,选择我的col为nummeric的所有列。

然后在该视图中执行选择以转换varchar字段。

您可以看到的另一件事是您的表格设计,以消除演员阵容的需要。

修改

  • 是否有些数字大于bigint?
  • 是否有空格,领先,尾随或数字?
  • 有格式字符吗?小数点?

答案 7 :(得分:0)

尝试使用:

SELECT 
  ID, 
  CAST(MyCol AS bigint) as MyCol
FROM
(
  SELECT TOP (100) PERCENT 
      ID, 
      MyCol 
  FROM 
      MyTable 
  WHERE 
      (isnumeric(MyCol) = 1)
) as tmp

这应该有效,因为内部选择仅返回数值,因此外部选择可以将第一个选择中的所有值转换为数字。似乎在你自己的代码中,SQL在执行isnumeric函数之前尝试强制转换(也许它与优化有关)。