简体   繁体   English

SQL Server,其中field是int?

[英]SQL Server, where field is int?

how can I accomplish: 我怎样才能完成:

select * from table where column_value is int

I know I can probably inner join to the system tables and type tables but I'm wondering if there's a more elegant way. 我知道我可能内部加入系统表和类型表但我想知道是否有更优雅的方式。

Note that column_value is a varchar that "could" have an int, but not necessarily. 请注意,column_value是一个“可能”具有int的varchar,但不一定。

Maybe I can just cast it and trap the error? 也许我可以抛出它并捕获错误? But again, that seems like a hack. 但同样,这似乎是一个黑客。

select * from table
where column_value not like '[^0-9]'

If negative ints are allowed, you need something like 如果允许负值,你需要类似的东西

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

You need more code if column_value can be an integer that exceeds the limits of the "int" type, and you want to exclude such cases. 如果column_value可以是超出“int”类型限制的整数,并且您希望排除这种情况,则需要更多代码。

Here if you want to implement your custom function 在这里,如果您想实现自定义功能

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 returns 1 when the input expression evaluates to a valid integer, floating point number, money or decimal type ; 当输入表达式求值为有效整数, 浮点数,货币或小数类型时,ISNUMERIC返回1; otherwise it returns 0. A return value of 1 guarantees that expression can be converted to one of these numeric types. 否则返回0.返回值1保证表达式可以转换为这些数字类型之一。

This should handle all cases without throwing any exceptions: 这应该处理所有情况而不抛出任何例外:

--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]

Throw this into a Scalar UDF and call it ReturnInt() . 把它扔进Scalar UDF并称之为ReturnInt()
If the value comes back as NULL, then it's not an int (so there's your IsInteger() requirement) 如果值返回为NULL,那么它不是int(所以有你的IsInteger()要求)

If you don't like typing " WHERE ReturnInt(SomeValue) IS NOT NULL ", you could throw it into another scalar UDF called IsInt() to call this function and simply return " ReturnInt(SomeValue) IS NOT NULL ". 如果您不喜欢键入“ WHERE ReturnInt(SomeValue)IS NOT NULL ”,您可以将其抛入另一个名为IsInt()的标量UDF来调用此函数并简单地返回“ ReturnInt(SomeValue)IS NOT NULL ”。

The cool thing is, the UDF can serve double duty by returning the " safely " converted int value. 很酷的是,UDF可以通过返回“ 安全 ”转换的int值来提供双重任务。
Just because something can be an int doesn't mean casting it as an int won't throw a huge exception. 只是因为某些东西可以是一个int并不意味着将它作为一个int而不会抛出一个巨大的例外。 This takes care of that for you. 这会照顾你。

Also, I'd avoid the other solutions because this universal approach will handle commas, decimals, dollar signs, and checks the acceptable Int value's range while the other solutions do not - or they require multiple SET operations that prevent you from using the logic in a Scalar-Function for maximum performance. 此外,我会避免其他解决方案,因为这种通用方法将处理逗号,小数,美元符号,并检查可接受的Int值的范围,而其他解决方案不 - 或者它们需要多个SET操作,阻止您使用逻辑标量函数以获得最佳性能。

See the examples below and test them against my code and others: 请参阅下面的示例,并根据我的代码和其他代码测试它们:

--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.


Update: 更新:
I read a comment here that you want to be able to parse a value like '123.' 我在这里读到一条评论,你希望能够解析像'123这样的值。 into an Integer. 变成整数。 I have updated my code to handle this as well. 我已经更新了我的代码来处理这个问题。

Note: This converts "1.0", but returns null on "1.9". 注意:这会转换为“1.0”,但在“1.9”上返回null。
If you want to allow for rounding, then tweak the logic in the "THEN" clause to add Round() like so: 如果你想允许舍入,那么调整“THEN”子句中的逻辑来添加Round(),如下所示:
ROUND(CAST(REPLACE(REPLACE(@IntString,'$',''),',','') as Decimal(10)), 0) ROUND(CAST(REPLACE(REPLACE(@IntString,'$',''),',','')为Decimal(10)),0)
You must also remove the "AND" that checks for "decimal-points" to allow for Rounding or Truncation. 您还必须删除检查“小数点”的“AND”以允许舍入或截断。

Why not use the following and test for 1? 为什么不使用以下内容并测试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

I would do a UDF as Svetlozar Angelov suggests, but I would check for ISNUMERIC first (and return 0 if not), and then check for column_value % 1 = 0 to see if it's an integer. 我会像Svetlozar Angelov建议的那样做一个UDF,但我会首先检查ISNUMERIC(如果没有则返回0),然后检查column_value % 1 = 0以查看它是否为整数。

Here's what the body might look like. 这是身体的样子。 You have to put the modulo logic in a separate branch because it will throw an exception if the value isn't numeric. 您必须将模数逻辑放在一个单独的分支中,因为如果该值不是数字,它将抛出异常。

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

If you are purely looking to verify a string is all digits and not just CAST-able to INT you can do this terrible, terrible thing: 如果你纯粹想要验证一个字符串是全部数字而不仅仅是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','')
)

It returns 0 when the string was empty or pure digits. 当字符串为空或纯数字时,它返回0。

To make it a useful check for "poor-man's" Integer you'd have to deal with empty string, and an initial negative sign. 为了使它成为“穷人”整数的有用检查,你必须处理空字符串和一个初始的负号。 And manually make sure it isn't too long for your variety of INTEGER. 并且手动确保它对于各种INTEGER来说不会太长。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM