【问题标题】:SQL Server, where field is int?SQL Server,字段在哪里?
【发布时间】:2014-02-18 05:34:27
【问题描述】:

我该如何完成:

select * from table where column_value is int

我知道我可能可以内部连接到系统表和类型表,但我想知道是否有更优雅的方式。

请注意,column_value 是一个“可能”具有 int 的 varchar,但不一定。

也许我可以直接转换它并捕获错误?但同样,这似乎是一种 hack。

【问题讨论】:

  • 老实说,这里的 hack 是您在文本列中有数据,您想将其视为数字。你真的不应该那样做,但我想你已经发现了原因。

标签: sql sql-server-2005 tsql entity-attribute-value


【解决方案1】:
select * from table
where column_value not like '[^0-9]'

如果允许负整数,则需要类似

where column_value like '[+-]%' 
and substring(column_value,patindex('[+-]',substring(column_value,1))+1,len(column_value))
not like '[^0-9]'

如果 column_value 可以是超出“int”类型限制的整数,并且您希望排除此类情况,则需要更多代码。

【讨论】:

  • 不确定这是否正确,但这不会只测试第一个字符是否为“不是数字”吗?你不应该使用:WHERE column_value not like '%[^0-9]%'?
  • OR column_value like '%[0-9]%'?
【解决方案2】:

如果你想实现你的自定义函数在这里

CREATE Function dbo.IsInteger(@Value VARCHAR(18))
RETURNS BIT
AS 
BEGIN    
     RETURN ISNULL(     
         (SELECT    CASE WHEN CHARINDEX('.', @Value) > 0 THEN 
                            CASE WHEN CONVERT(int, PARSENAME(@Value, 1)) <> 0  THEN 0  ELSE 1 END  
                    ELSE 1 
                    END      
          WHERE     ISNUMERIC(@Value + 'e0') = 1), 0)

END

ISNUMERIC 在输入时返回 1 表达式计算为有效 整数、浮点数、金钱 或十进制类型;否则返回 0. 返回值 1 保证表达式可以转换为以下之一 这些数字类型。

【讨论】:

  • 它检测到“123”。作为整数,但我们不能转换它:(
【解决方案3】:

我会按照 Svetlozar Angelov 的建议进行 UDF,但我会先检查 ISNUMERIC(如果不是则返回 0),然后检查 column_value % 1 = 0 以查看它是否为整数。

这是身体的样子。您必须将模逻辑放在单独的分支中,因为如果值不是数字,它将引发异常。

DECLARE @RV BIT
IF ISNUMERIC(@value) BEGIN
    IF CAST(@value AS NUMERIC) % 1 = 0 SET @RV = 1
    ELSE SET @RV = 0
END
ELSE SET @RV = 0
RETURN @RV

【讨论】:

    【解决方案4】:

    这应该处理所有情况而不抛出任何异常:

    --This handles dollar-signs, commas, decimal-points, and values too big or small,
    --  all while safely returning an int.
    DECLARE @IntString as VarChar(50) = '$1,000.'
    SELECT CAST((CASE WHEN --This IsNumeric check here does most of the heavy lifting.  The rest is Integer-Specific
                           ISNUMERIC(@IntString) = 1
                           --Only allow Int-related characters.  This will exclude things like 'e' and other foreign currency characters.
                       AND @IntString NOT LIKE '%[^ $,.\-+0-9]%' ESCAPE '\'--'
                           --Checks that the value is not out of bounds for an Integer.
                       AND CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38)) BETWEEN -2147483648 AND 2147483647
                           --This allows values with decimal-points for count as an Int, so long as there it is not a fractional value.
                       AND CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38)) = CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(38,2))
                           --This will safely convert values with decimal points to casting later as an Int.
                      THEN CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(10))
                 END) as Int)[Integer]
    

    将其放入标量 UDF 中并调用它ReturnInt()
    如果该值返回为 NULL,则它不是 int(因此有您的 IsInteger() 要求)

    如果您不喜欢输入“WHERE ReturnInt(SomeValue) IS NOT NULL”,您可以将其放入另一个名为 IsInt() 的标量 UDF 中来调用它函数并简单地返回“ReturnInt(SomeValue) IS NOT NULL”。

    很酷的是,UDF 可以通过返回“安全”转换的 int 值来提供双重任务。
    仅仅因为 可以 是 int 并不意味着将其转换为 int 不会引发巨大的异常。这会为您解决这个问题。

    另外,我会避免使用其他解决方案,因为这种通用方法将处理逗号、小数、美元符号,并检查可接受的 Int 值的范围,而其他解决方案则不这样做 - 或者它们需要多个 SET 操作来阻止您使用标量函数中的逻辑以获得最佳性能。

    查看下面的示例并针对我的代码和其他代码进行测试:

    --Proves that appending "e0" or ".0e0" is NOT a good idea.
    select ISNUMERIC('$1' + 'e0')--Returns: 0.
    select ISNUMERIC('1,000' + 'e0')--Returns: 0.
    select ISNUMERIC('1.0' + '.0e0')--Returns: 0.
    
    --While these are numeric, they WILL break your code
    --   if you try to cast them directly as int.
    select ISNUMERIC('1,000')--Returns: 1.
    select CAST('1,000' as Int)--Will throw exception.
    select ISNUMERIC('$1')--Returns: 1.
    select CAST('$1' as Int)--Will throw exception.
    select ISNUMERIC('10.0')--Returns: 1.
    select CAST('10.0' as Int)--Will throw exception.
    select ISNUMERIC('9999999999223372036854775807')--Returns: 1.  This is why I use Decimal(38) as Decimal defaults to Decimal(18).
    select CAST('9999999999223372036854775807' as Int)--Will throw exception.
    


    更新:
    我在这里阅读了一条评论,您希望能够解析像“123”这样的值。成一个整数。我也更新了我的代码来处理这个问题。

    注意:这会转换“1.0”,但会在“1.9”上返回 null。
    如果您想允许舍入,则调整“THEN”子句中的逻辑以添加 Round(),如下所示:
    ROUND(CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(10)), 0)
    必须还删除检查“小数点”的“AND”以允许舍入或截断。

    【讨论】:

      【解决方案5】:

      为什么不使用以下内容并测试 1?

      DECLARE @TestValue nvarchar(MAX)
      SET @TestValue = '1.04343234e5'
      
      SELECT CASE WHEN ISNUMERIC(@TestValue) = 1
              THEN CASE WHEN ROUND(@TestValue,0,1) = @TestValue
                  THEN 1
                  ELSE 0
                  END
              ELSE null
              END AS Analysis
      

      【讨论】:

        【解决方案6】:

        如果您只是想验证一个字符串是所有数字,而不仅仅是 CAST 到 INT,那么您可以做这件可怕的事情:

        select LEN(
         REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE(
         '-1.223344556677889900e-1'
         ,'0','') ,'1','') ,'2','') ,'3','') ,'4','') ,'5','') ,'6','') ,'7','') ,'8','') ,'9','')
        )
        

        当字符串为空或纯数字时返回0。

        要使其成为“穷人”整数的有用检查,您必须处理空字符串和初始负号。并手动确保它对于您的各种 INTEGER 来说不会太长。

        【讨论】:

          猜你喜欢
          • 2010-10-02
          • 2011-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-12
          • 1970-01-01
          • 2011-10-09
          相关资源
          最近更新 更多