【问题标题】:How to use Isnumeric in dynamic sql?如何在动态sql中使用Isnumeric?
【发布时间】:2016-02-23 19:16:06
【问题描述】:

我需要知道如何从 varchar 数据类型的 outputformula 列中获取数值。

我在动态 sql 查询中使用这个 outputformula 列来执行数学计算。

我有下面的表格代码和用于获取值的选择查询。

Create table #table1
(
IDNUM  int,
outputformula  varchar(60)
)

insert into #table1
values 
(1, '67349.000 +78343.000'),
(2, 'a +78343.000'),
(3, '45783.00+b'),
(4, '6152.000 +1524.000'),
(5, 'cda +7151.000'),
(6, '67349.000 +78343.000')

    Select outputformula from #table1 where ISNUMERIC(outputformula) =1

当我执行代码时,我没有得到任何值,有没有办法只输出除列中的字母之外的数值......

我应该得到输出列

 67349.000 +78343.000
 6152.000 +1524.000
 67349.000 +78343.000

【问题讨论】:

  • 看起来您必须查找拆分器来拆分字符串(使用空格作为分隔符),然后在返回时使用 ISNUMERIC 函数。
  • 你是怎么得到NULLs的?您的查询根本不返回任何行。你能用你的预期结果编辑你的问题吗?
  • 你最好写一个 UDF,而不是试图强行使用 ISNUMERIC。
  • ISNUMERIC 是一个可怕的命名函数。它应该更像 IsTheValueSomethingThatCanBeConvertedToAnyDatatypeThatIsRoughlyNumberOriented。当然,这完全是太长了。但是 IsNumeric 会返回很多误报。 1e2 或 $ 都评估为真。
  • 大家好......感谢 cmets......我需要输出用于在动态 SQL 中进行数学运算......因此我刚刚添加了一些编辑......

标签: sql sql-server sql-server-2012


【解决方案1】:

很遗憾,ISNUMERIC 不计算公式。您可以尝试在 SQL 函数中编写自己的简单解析器,但函数不允许任何类型的错误处理,因此当您尝试评估其中一个非数字方程时,您会遇到问题。

您最好的选择可能是使用您用来评估这些方程式的任何东西来执行此任务 - 我假设这是在某种前端。

由于您没有使用前端,因此这是我能想到的最好的直接 SQL 方法。首先,创建一个可以计算仅数值方程的存储过程。这作为一个函数会更好,但不幸的是函数不允许 TRY..CATCH 块,这对于处理非数字方程至关重要。以下是此类存储过程的示例:

CREATE PROCEDURE dbo.Check_Dynamic_Formula
    @formula VARCHAR(60),
    @result DECIMAL(10, 4) OUTPUT
AS
BEGIN
    DECLARE
        @sql NVARCHAR(100)

    BEGIN TRY
        SELECT @sql = 'SELECT @inner_result = ' + @formula

        EXEC sp_executesql @sql, N'@inner_result DECIMAL(10, 4) OUTPUT', @inner_result = @result OUTPUT
    END TRY
    BEGIN CATCH
        SELECT @result = NULL
    END CATCH
END

一旦你有了它,你就可以设置一个CURSOR 来一次通过你的表一行(这就是为什么标量函数会更好,因为你可以避免CURSOR)。检查表中每一行的输出变量。如果是NULL,则存储过程无法评估它。

一些重要的警告...

在某些情况下,评估可能会无意中变成数字 - 请参阅 @Sean Lange 对您的问题的评论。

重要这很容易被注入。我不会针对任何可供用户生成的数据运行此程序。例如,如果您有用户输入公式,那么他们可能会进行 SQL 注入攻击。

最后,如果TRY..CATCH 块中出现任何其他错误,它将使它看起来好像该行是非数字的。我们指望代码无法证明它是非数字的,这是一种脆弱的方法。任何错误都可能给您带来误报。

【讨论】:

  • 嗨,汤姆...感谢 cmets... 不幸的是,我在使用 dynamicsql 的存储过程中使用了整个评估...您有什么替代方法可以建议吗?
【解决方案2】:

如果您的所有字符串都采用 {token1}blank{token2} 格式,一种方法是在您的数据库中定义 Split 函数并使用以下代码:

Select T.*, T1.StringValue, ISNUMERIC(T1.StringValue), T2.StringValue, ISNUMERIC(T2.StringValue), ISNUMERIC(T1.StringValue) * ISNUMERIC(T2.StringValue) AS IsNumeric
from #table1 T
cross apply dbo.Split(T.outputformula, ' ') T1 
cross apply dbo.Split(T.outputformula, ' ') T2 
where T1.Ordinal = 1 and T2.Ordinal = 2

但是,您应该考虑到SQL ISNUMERIC 函数有一些限制并提供some false positives

进行更具体的数字检查的一种方法是使用TRY_CONVERT 函数。

【讨论】:

    【解决方案3】:

    ISNUMERIC 只会返回 1 或 0。在这种情况下,您要求报表在 outputformula 列中返回任何数字,但由于您将该字段声明为 VARCHAR(60),因此这将始终返回 0 个结果。

    查看此其他帖子,了解您的问题的潜在答案。

    Query to get only numbers from a string

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 2021-06-25
      • 1970-01-01
      • 2011-07-22
      • 1970-01-01
      • 2012-02-12
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多