检查字符是不是为数字的最快方法?

Posted

技术标签:

【中文标题】检查字符是不是为数字的最快方法?【英文标题】:Fastest way to check if a character is a digit?检查字符是否为数字的最快方法? 【发布时间】:2018-05-04 09:38:25 【问题描述】:

我在使用 sqlserver 的 ISNUMERIC 函数时遇到问题,它为 ',' 返回 true

我正在解析邮政编码并尝试查看第二个字符(应该是数字)是否为 0,并在每种情况下执行不同的操作。问题是我不能通过首先检查 isNumeric 来转换字符。这是我的标量值函数的代码,用于返回第二个字符位置中的数字,如果不是数字,则返回 -1。

@declare firstDigit int

IF ISNUMERIC(SUBSTRING(@postal,2,1) AS int) = 1
   set @firstDigit = CAST(SUBSTRING(@postal,2,1) AS int)
ELSE
   set @firstDigit = -1       

RETURN @firstdigit

因为当邮政编码不完全有效时,这会失败。我只是想找出如何检查 nvarchar @postal 的第二个字符是否是 0-9 之间的数字。我见过不同类型的解决方案,例如使用LIKE [0-9] 或使用PATINDEX 等。

有没有更好/更简单的方法来做到这一点,如果没有,哪种方法最快?

编辑:根据 Aaron Bertrand 的建议添加代码

ON z.postal = 
   CASE
      WHEN CONVERT(INT, CASE WHEN SUBSTRING(v.patientPostal,2,1) LIKE '[0-9]' 
          THEN SUBSTRING(v.patientPostal, 2,1) END) = 0 then v.patientPostal
      WHEN CONVERT(INT, CASE WHEN SUBSTRING(v.patientPostal,2,1) LIKE '[0-9]' 
          THEN SUBSTRING(v.patientPostal, 2,1) END) > 0 then LEFT(v.patientPostal,3)

【问题讨论】:

您能发布更多代码吗?我认为它在非数字第二位上失败的原因可能与您显示的 IF 子句后面的内容有关。 差不多就是这样,我创建了一个标量值函数来返回数字,如果不是,则返回-1。如果有帮助,我可以用整个功能更新它。 谢谢,我会调查的,所以你认为我应该在原地完成整个检查并使用 like 吗?我没有意识到标量 UDF 有点受打击,我只使用 sqlserver 很短的时间 哪些模式有好有坏?每个国家/地区的邮政编码都不同... 我只是在那里寻找一个数字,我正在查看的邮政编码模式仅与加拿大安大略省有关,例如 A1B2C3 【参考方案1】:

如果您能够检测到 WHERE col LIKE '[0-9]' 与您想出的任何其他方法之间的任何区别,我会感到非常惊讶。但我同意 Denis 的观点,将其放在一个函数中,以便您在所有代码中始终使用相同的检查(或者至少,如果您因为大扫描等原因避免使用 UDF,请在您的代码中放置一个标记,它将便于以后进行大规模更改)。

也就是说,与在函数内部使用解析方法相比,使用标量 UDF 肯定会对性能产生更大的影响。您真的应该比较 UDF 的性能与使用 CASE 进行内联的性能。例如

SELECT Postal = CONVERT(INT, CASE WHEN SUBSTRING(postal,2,1) LIKE '[0-9]' 
       THEN SUBSTRING(postal, 2,1) END)
FROM ...

如果字符不是数字,这将产生NULL

如果您只处理检查局部变量,那么您使用什么解析方法实际上并不重要,您最好将优化工作集中在其他地方。

EDIT 向演示的JOIN 子句添加建议。这可能会导致更少的持续扫描,但更具可读性(更少的子字符串调用等):

;WITH v AS 
(
    SELECT /* other columns, */ patientPostal, 
      ss = SUBSTRING(v.patientPostal,2,1),
      FROM [whatever table is aliased v in current query]
)
SELECT /* column list */
FROM [whatever table is aliased z in current query]
INNER JOIN v ON z.postal = CONVERT(INT, CASE 
    WHEN v.ss = '0' THEN ss
    WHEN v.ss LIKE '[1-9]' THEN LEFT(v.patientPostal, 3)
END);

【讨论】:

感谢您的信息,我没有意识到标量 UDF 有点受欢迎。我将在新代码中进行编辑,使其更有意义。我试图将检查移到函数之外,因为它已经很忙并且它位于 case 语句本身的内部。但是,如果这样做更成功,我可以在函数中添加一些额外的代码。 经常是,但并非总是如此。这取决于 UDF 何时被击中;例如,如果您的查询只返回一行,它可能不仅被调用一次,而且与很多事情一样它取决于 所以我已经编辑了我的 join 语句的 on 子句的样子。保留它是最快的还是我会从将支票转移到自己的功能中受益? 感谢您提供的所有信息,我只是尝试了两种方式,内联方式花费了 9 秒,而旧方式花费了 1:11 我们称之为#SQLWinning。 :-)【参考方案2】:

最好的方法是:

IF SUBSTRING(@postal,2,1) LIKE [0-9]
CAST(SUBSTRING(@postal,2,1) AS int)

【讨论】:

只是为了扮演魔鬼的拥护者,为什么那是“最好的”?相对于什么? "best" 可能有点强。考虑到使用 LIKE [0-9] 而不添加 UDF 以实现可重复性的要求,他现在可以开始运行了。他可能只能修改该脚本;添加 UDF 可能超出范围或没有时间进行的其他测试。因此,在最佳情况下,您的答案要好得多;在非最佳情况下,无论它如何发生,“使这项工作”都是可能的结果。【参考方案3】:

看看IsNumeric, IsInt, IsNumber,它检查了这三种类型

【讨论】:

以上是关于检查字符是不是为数字的最快方法?的主要内容,如果未能解决你的问题,请参考以下文章

在 JavaScript 中检查字符串是不是包含另一个子字符串的最快方法?

检查字符数组是不是为零的快速方法[重复]

如何检查字符串是不是为数字? [复制]

在 NetworkX 中检查子图是不是为集团的最快方法

检查内存是不是清零的最快方法

如何检查字符串输入是不是为数字?