มีวิธีใน T-SQL ในการแคสต์ nvarchar เป็น int และส่งคืนค่าเริ่มต้นหรือ NULL หากการแปลงล้มเหลว?
มีวิธีใน T-SQL ในการแคสต์ nvarchar เป็น int และส่งคืนค่าเริ่มต้นหรือ NULL หากการแปลงล้มเหลว?
คำตอบ:
ใช้ฟังก์ชั่น TRY_CONVERT
สร้างฟังก์ชันที่ผู้ใช้กำหนด สิ่งนี้จะหลีกเลี่ยงปัญหาที่Fedor Hajdu กล่าวถึงเกี่ยวกับสกุลเงินตัวเลขเศษส่วน ฯลฯ :
CREATE FUNCTION dbo.TryConvertInt(@Value varchar(18))
RETURNS int
AS
BEGIN
SET @Value = REPLACE(@Value, ',', '')
IF ISNUMERIC(@Value + 'e0') = 0 RETURN NULL
IF ( CHARINDEX('.', @Value) > 0 AND CONVERT(bigint, PARSENAME(@Value, 1)) <> 0 ) RETURN NULL
DECLARE @I bigint =
CASE
WHEN CHARINDEX('.', @Value) > 0 THEN CONVERT(bigint, PARSENAME(@Value, 2))
ELSE CONVERT(bigint, @Value)
END
IF ABS(@I) > 2147483647 RETURN NULL
RETURN @I
END
GO
-- Testing
DECLARE @Test TABLE(Value nvarchar(50)) -- Result
INSERT INTO @Test SELECT '1234' -- 1234
INSERT INTO @Test SELECT '1,234' -- 1234
INSERT INTO @Test SELECT '1234.0' -- 1234
INSERT INTO @Test SELECT '-1234' -- -1234
INSERT INTO @Test SELECT '$1234' -- NULL
INSERT INTO @Test SELECT '1234e10' -- NULL
INSERT INTO @Test SELECT '1234 5678' -- NULL
INSERT INTO @Test SELECT '123-456' -- NULL
INSERT INTO @Test SELECT '1234.5' -- NULL
INSERT INTO @Test SELECT '123456789000000' -- NULL
INSERT INTO @Test SELECT 'N/A' -- NULL
SELECT Value, dbo.TryConvertInt(Value) FROM @Test
ข้อมูลอ้างอิง:ฉันใช้หน้านี้อย่างกว้างขวางเมื่อสร้างโซลูชันของฉัน
ครับ :). ลองสิ่งนี้:
DECLARE @text AS NVARCHAR(10)
SET @text = '100'
SELECT CASE WHEN ISNUMERIC(@text) = 1 THEN CAST(@text AS INT) ELSE NULL END
-- returns 100
SET @text = 'XXX'
SELECT CASE WHEN ISNUMERIC(@text) = 1 THEN CAST(@text AS INT) ELSE NULL END
-- returns NULL
ISNUMERIC()
มีไม่กี่ประเด็นชี้โดยชาเลีย Hajdu
มันกลับเป็นจริงสำหรับสตริงเช่น$
(สกุลเงิน) ,
หรือ.
(ทั้งสองเป็นตัวคั่น) และ+
-
ISNUMERIC
สำหรับคำตอบนี้ที่จะใช้กับข้อมูลที่ไม่ได้รับการISNUMERIC
ตรวจสอบ(และคุณไม่จำเป็นต้องตรวจสอบตั้งแต่แรกสำหรับข้อมูลที่ได้รับการตรวจสอบอย่างถูกต้อง) ผู้เขียนยอมรับว่ามีปัญหาเหล่านี้ แต่ไม่ได้กล่าวถึงประเด็นเหล่านี้
TRY_CONVERT
/ TRY_CAST
ซึ่งมีจุดประสงค์เพื่อแก้ไขคำถามของ OP อย่างชัดเจน คำตอบนี้เขียนขึ้นก่อนที่ SQL 2012 จะเผยแพร่
ฉันอยากจะสร้างฟังก์ชันเช่น TryParse หรือใช้TRY-CATCH
บล็อกT-SQL เพื่อให้ได้สิ่งที่คุณต้องการ
ISNUMERIC ไม่ทำงานตามที่ตั้งใจไว้เสมอไป รหัสที่ให้ไว้ก่อนหน้านี้จะล้มเหลวหากคุณทำ:
SET @text = '$'
เครื่องหมาย $ สามารถแปลงเป็นประเภทข้อมูลเงินได้ดังนั้นจึงISNUMERIC()
คืนค่าจริงในกรณีนั้น มันจะทำเช่นเดียวกันสำหรับ '-' (ลบ), ',' (ลูกน้ำ) และ '.' ตัวละคร
ISNUMERIC()
ผลตอบแทน1
ยัง,
และ.
.
ดังที่ได้กล่าวไปแล้วคุณอาจพบปัญหาหลายประการหากคุณใช้ISNUMERIC
:
-- Incorrectly gives 0:
SELECT CASE WHEN ISNUMERIC('-') = 1 THEN CAST('-' AS INT) END
-- Error (conversion failure):
SELECT CASE WHEN ISNUMERIC('$') = 1 THEN CAST('$' AS INT) END
SELECT CASE WHEN ISNUMERIC('4.4') = 1 THEN CAST('4.4' AS INT) END
SELECT CASE WHEN ISNUMERIC('1,300') = 1 THEN CAST('1,300' AS INT) END
-- Error (overflow):
SELECT CASE WHEN ISNUMERIC('9999999999') = 1 THEN CAST('9999999999' AS INT) END
หากคุณต้องการการแปลงที่เชื่อถือได้คุณจะต้องเขียนโค้ดด้วยตัวเอง
อัปเดต : คำแนะนำใหม่ของฉันคือการใช้การแปลงการทดสอบตัวกลางFLOAT
เพื่อตรวจสอบหมายเลข วิธีการนี้จะขึ้นอยู่กับความคิดเห็นของ adrianm ตรรกะสามารถกำหนดเป็นฟังก์ชันค่าตารางแบบอินไลน์ได้:
CREATE FUNCTION TryConvertInt (@text NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(
SELECT
CASE WHEN ISNUMERIC(@text + '.e0') = 1 THEN
CASE WHEN CONVERT(FLOAT, @text) BETWEEN -2147483648 AND 2147483647
THEN CONVERT(INT, @text)
END
END AS [Result]
)
การทดสอบบางอย่าง:
SELECT [Conversion].[Result]
FROM ( VALUES
( '1234' ) -- 1234
, ( '1,234' ) -- NULL
, ( '1234.0' ) -- NULL
, ( '-1234' ) -- -1234
, ( '$1234' ) -- NULL
, ( '1234e10' ) -- NULL
, ( '1234 5678' ) -- NULL
, ( '123-456' ) -- NULL
, ( '1234.5' ) -- NULL
, ( '123456789000000' ) -- NULL
, ( 'N/A' ) -- NULL
, ( '-' ) -- NULL
, ( '$' ) -- NULL
, ( '4.4' ) -- NULL
, ( '1,300' ) -- NULL
, ( '9999999999' ) -- NULL
, ( '00000000000000001234' ) -- 1234
, ( '212110090000000235698741' ) -- NULL
) AS [Source] ([Text])
OUTER APPLY TryConvertInt ([Source].[Text]) AS [Conversion]
ผลลัพธ์จะคล้ายกับ คำตอบของ Joseph Sturtevantโดยมีข้อแตกต่างหลัก ๆ ดังนี้
.
หรือ,
เพื่อเลียนแบบพฤติกรรมของINT
การแปลงเนทีฟ '1,234'
และ'1234.0'
NULL
ผลตอบแทน'00000000000000001234'
12
เพิ่มความยาวพารามิเตอร์จะส่งผลให้เกิดข้อผิดพลาดเกี่ยวกับตัวเลขที่ล้นBIGINT
เช่นBBANs (หมายเลขบัญชีธนาคารพื้นฐาน) '212110090000000235698741'
เช่นถอน : แนวทางด้านล่างไม่แนะนำอีกต่อไปเนื่องจากเหลือไว้เพียงเพื่อการอ้างอิง
ตัวอย่างด้านล่างใช้กับจำนวนเต็มที่ไม่ใช่จำนวนเต็มลบ ตรวจสอบว่าสตริงของคุณไม่มีอักขระที่ไม่ใช่ตัวเลขไม่ว่างเปล่าและไม่ล้น (โดยเกินค่าสูงสุดสำหรับint
ประเภท) อย่างไรก็ตามยังให้NULL
สำหรับจำนวนเต็มที่ถูกต้องซึ่งมีความยาวเกิน 10 อักขระเนื่องจากเลขศูนย์นำหน้า
SELECT
CASE WHEN @text NOT LIKE '%[^0-9]%' THEN
CASE WHEN LEN(@text) BETWEEN 1 AND 9
OR LEN(@text) = 10 AND @text <= '2147483647'
THEN CAST (@text AS INT)
END
END
หากคุณต้องการสนับสนุนเลขศูนย์นำหน้าให้ใช้ด้านล่าง CASE
คำสั่งที่ซ้อนกันแม้ว่าจะดูเทอะทะ แต่ก็จำเป็นเพื่อส่งเสริมการประเมินการลัดวงจรและลดโอกาสที่จะเกิดข้อผิดพลาด (เช่นจากการส่งผ่านความยาวเชิงลบไปจนถึงLEFT
)
SELECT
CASE WHEN @text NOT LIKE '%[^0-9]%' THEN
CASE WHEN LEN(@text) BETWEEN 1 AND 9 THEN CAST (@text AS INT)
WHEN LEN(@text) >= 10 THEN
CASE WHEN LEFT(@text, LEN(@text) - 10) NOT LIKE '%[^0]%'
AND RIGHT(@text, 10) <= '2147483647'
THEN CAST (@text AS INT)
END
END
END
หากคุณต้องการสนับสนุนจำนวนเต็มบวกและลบด้วยเลขศูนย์นำหน้าจำนวนเท่าใดก็ได้:
SELECT
-- Positive integers (or 0):
CASE WHEN @text NOT LIKE '%[^0-9]%' THEN
CASE WHEN LEN(@text) BETWEEN 1 AND 9 THEN CAST (@text AS INT)
WHEN LEN(@text) >= 10 THEN
CASE WHEN LEFT(@text, LEN(@text) - 10) NOT LIKE '%[^0]%'
AND RIGHT(@text, 10) <= '2147483647'
THEN CAST (@text AS INT)
END
END
-- Negative integers:
WHEN LEFT(@text, 1) = '-' THEN
CASE WHEN RIGHT(@text, LEN(@text) - 1) NOT LIKE '%[^0-9]%' THEN
CASE WHEN LEN(@text) BETWEEN 2 AND 10 THEN CAST (@text AS INT)
WHEN LEN(@text) >= 11 THEN
CASE WHEN SUBSTRING(@text, 2, LEN(@text) - 11) NOT LIKE '%[^0]%'
AND RIGHT(@text, 10) <= '2147483648'
THEN CAST (@text AS INT)
END
END
END
END
ความนับถือ.
ฉันเขียนฟังก์ชันสเกลาร์ที่มีประโยชน์เพื่อจำลองฟังก์ชัน TRY_CAST ของ SQL SERVER 2012 ใน SQL Server 2008
คุณสามารถดูได้ในลิงค์ถัดไปด้านล่างและเราจะช่วยกันปรับปรุง TRY_CAST ฟังก์ชันสำหรับ SQL Server 2008 https://gist.github.com/jotapardo/800881eba8c5072eb8d99ce6eb74c8bb
ความแตกต่างหลักสองประการคือคุณต้องส่งพารามิเตอร์ 3 ตัวและคุณต้องทำการแปลงหรือแคสต์อย่างชัดเจนไปยังฟิลด์เพิ่มเติม อย่างไรก็ตามยังคงมีประโยชน์อย่างมากเนื่องจากช่วยให้คุณสามารถคืนค่าเริ่มต้นได้หาก CAST ทำงานไม่ถูกต้อง
dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)
ตัวอย่าง:
SELECT CASE WHEN dbo.TRY_CAST('6666666166666212', 'INT', DEFAULT) IS NULL
THEN 'Cast failed'
ELSE 'Cast succeeded'
END AS Result;
ตอนนี้รองรับเฉพาะประเภทข้อมูลINT, DATE, NUMERIC, BIT และ FLOAT
ฉันหวังว่าคุณพบว่ามีประโยชน์.
รหัส:
DECLARE @strSQL NVARCHAR(1000)
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[TRY_CAST]'))
BEGIN
SET @strSQL = 'CREATE FUNCTION [dbo].[TRY_CAST] () RETURNS INT AS BEGIN RETURN 0 END'
EXEC sys.sp_executesql @strSQL
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
------------------------------------------------------------------------------------------------------------------------
Description:
Syntax
---------------
dbo.TRY_CAST(Expression, Data_Type, ReturnValueIfErrorCast)
+---------------------------+-----------------------+
| Expression | VARCHAR(8000) |
+---------------------------+-----------------------+
| Data_Type | VARCHAR(8000) |
+---------------------------+-----------------------+
| ReturnValueIfErrorCast | SQL_VARIANT = NULL |
+---------------------------+-----------------------+
Arguments
---------------
expression
The value to be cast. Any valid expression.
Data_Type
The data type into which to cast expression.
ReturnValueIfErrorCast
Value returned if cast fails or is not supported. Required. Set the DEFAULT value by default.
Return Type
----------------
Returns value cast to SQL_VARIANT type if the cast succeeds; otherwise, returns null if the parameter @pReturnValueIfErrorCast is set to DEFAULT,
or that the user indicates.
Remarks
----------------
dbo.TRY_CAST function simulates the TRY_CAST function reserved of SQL SERVER 2012 for using in SQL SERVER 2008.
dbo.TRY_CAST function takes the value passed to it and tries to convert it to the specified Data_Type.
If the cast succeeds, dbo.TRY_CAST returns the value as SQL_VARIANT type; if the cast doesn´t succees, null is returned if the parameter @pReturnValueIfErrorCast is set to DEFAULT.
If the Data_Type is unsupported will return @pReturnValueIfErrorCast.
dbo.TRY_CAST function requires user make an explicit CAST or CONVERT in ANY statements.
This version of dbo.TRY_CAST only supports CAST for INT, DATE, NUMERIC and BIT types.
Examples
====================================================================================================
--A. Test TRY_CAST function returns null
SELECT
CASE WHEN dbo.TRY_CAST('6666666166666212', 'INT', DEFAULT) IS NULL
THEN 'Cast failed'
ELSE 'Cast succeeded'
END AS Result;
GO
--B. Error Cast With User Value
SELECT
dbo.TRY_CAST('2147483648', 'INT', DEFAULT) AS [Error Cast With DEFAULT],
dbo.TRY_CAST('2147483648', 'INT', -1) AS [Error Cast With User Value],
dbo.TRY_CAST('2147483648', 'INT', NULL) AS [Error Cast With User NULL Value];
GO
--C. Additional CAST or CONVERT required in any assignment statement
DECLARE @IntegerVariable AS INT
SET @IntegerVariable = CAST(dbo.TRY_CAST(123, 'INT', DEFAULT) AS INT)
SELECT @IntegerVariable
GO
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp (
Id INT IDENTITY
, FieldNumeric NUMERIC(3, 1)
)
INSERT INTO dbo.#temp (FieldNumeric)
SELECT CAST(dbo.TRY_CAST(12.3, 'NUMERIC(3,1)', 0) AS NUMERIC(3, 1));--Need explicit CAST on INSERT statements
SELECT *
FROM #temp
DROP TABLE #temp
GO
--D. Supports CAST for INT, DATE, NUMERIC and BIT types.
SELECT dbo.TRY_CAST(2147483648, 'INT', 0) AS [Cast failed]
, dbo.TRY_CAST(2147483647, 'INT', 0) AS [Cast succeeded]
, SQL_VARIANT_PROPERTY(dbo.TRY_CAST(212, 'INT', 0), 'BaseType') AS [BaseType];
SELECT dbo.TRY_CAST('AAAA0101', 'DATE', DEFAULT) AS [Cast failed]
, dbo.TRY_CAST('20160101', 'DATE', DEFAULT) AS [Cast succeeded]
, SQL_VARIANT_PROPERTY(dbo.TRY_CAST('2016-01-01', 'DATE', DEFAULT), 'BaseType') AS [BaseType];
SELECT dbo.TRY_CAST(1.23, 'NUMERIC(3,1)', DEFAULT) AS [Cast failed]
, dbo.TRY_CAST(12.3, 'NUMERIC(3,1)', DEFAULT) AS [Cast succeeded]
, SQL_VARIANT_PROPERTY(dbo.TRY_CAST(12.3, 'NUMERIC(3,1)', DEFAULT), 'BaseType') AS [BaseType];
SELECT dbo.TRY_CAST('A', 'BIT', DEFAULT) AS [Cast failed]
, dbo.TRY_CAST(1, 'BIT', DEFAULT) AS [Cast succeeded]
, SQL_VARIANT_PROPERTY(dbo.TRY_CAST('123', 'BIT', DEFAULT), 'BaseType') AS [BaseType];
GO
--E. B. TRY_CAST return NULL on unsupported data_types
SELECT dbo.TRY_CAST(4, 'xml', DEFAULT) AS [unsupported];
GO
====================================================================================================
------------------------------------------------------------------------------------------------------------------------
Responsible: Javier Pardo
Date: diciembre 29/2016
WB tests: Javier Pardo
------------------------------------------------------------------------------------------------------------------------
Update by: Javier Eduardo Pardo Moreno
Date: febrero 16/2017
Id update: JEPM20170216
Description: Fix ISNUMERIC function makes it unreliable. SELECT dbo.TRY_CAST('+', 'INT', 0) will yield Msg 8114,
Level 16, State 5, Line 16 Error converting data type varchar to float.
ISNUMERIC() function treats few more characters as numeric, like: – (minus), + (plus), $ (dollar), \ (back slash), (.)dot and (,)comma
Collaborator aperiooculus (http://stackoverflow.com/users/3083382/aperiooculus )
Fix dbo.TRY_CAST('2013/09/20', 'datetime', DEFAULT) for supporting DATETIME format
WB tests: Javier Pardo
------------------------------------------------------------------------------------------------------------------------
*/
ALTER FUNCTION dbo.TRY_CAST
(
@pExpression AS VARCHAR(8000),
@pData_Type AS VARCHAR(8000),
@pReturnValueIfErrorCast AS SQL_VARIANT = NULL
)
RETURNS SQL_VARIANT
AS
BEGIN
--------------------------------------------------------------------------------
-- INT
--------------------------------------------------------------------------------
IF @pData_Type = 'INT'
BEGIN
IF ISNUMERIC(@pExpression) = 1 AND @pExpression NOT IN ('-','+','$','.',',','\') --JEPM20170216
BEGIN
DECLARE @pExpressionINT AS FLOAT = CAST(@pExpression AS FLOAT)
IF @pExpressionINT BETWEEN - 2147483648.0 AND 2147483647.0
BEGIN
RETURN CAST(@pExpressionINT as INT)
END
ELSE
BEGIN
RETURN @pReturnValueIfErrorCast
END --FIN IF @pExpressionINT BETWEEN - 2147483648.0 AND 2147483647.0
END
ELSE
BEGIN
RETURN @pReturnValueIfErrorCast
END -- FIN IF ISNUMERIC(@pExpression) = 1
END -- FIN IF @pData_Type = 'INT'
--------------------------------------------------------------------------------
-- DATE
--------------------------------------------------------------------------------
IF @pData_Type IN ('DATE','DATETIME')
BEGIN
IF ISDATE(@pExpression) = 1
BEGIN
DECLARE @pExpressionDATE AS DATETIME = cast(@pExpression AS DATETIME)
IF @pData_Type = 'DATE'
BEGIN
RETURN cast(@pExpressionDATE as DATE)
END
IF @pData_Type = 'DATETIME'
BEGIN
RETURN cast(@pExpressionDATE as DATETIME)
END
END
ELSE
BEGIN
DECLARE @pExpressionDATEReplaced AS VARCHAR(50) = REPLACE(REPLACE(REPLACE(@pExpression,'\',''),'/',''),'-','')
IF ISDATE(@pExpressionDATEReplaced) = 1
BEGIN
IF @pData_Type = 'DATE'
BEGIN
RETURN cast(@pExpressionDATEReplaced as DATE)
END
IF @pData_Type = 'DATETIME'
BEGIN
RETURN cast(@pExpressionDATEReplaced as DATETIME)
END
END
ELSE
BEGIN
RETURN @pReturnValueIfErrorCast
END
END --FIN IF ISDATE(@pExpression) = 1
END --FIN IF @pData_Type = 'DATE'
--------------------------------------------------------------------------------
-- NUMERIC
--------------------------------------------------------------------------------
IF @pData_Type LIKE 'NUMERIC%'
BEGIN
IF ISNUMERIC(@pExpression) = 1
BEGIN
DECLARE @TotalDigitsOfType AS INT = SUBSTRING(@pData_Type,CHARINDEX('(',@pData_Type)+1, CHARINDEX(',',@pData_Type) - CHARINDEX('(',@pData_Type) - 1)
, @TotalDecimalsOfType AS INT = SUBSTRING(@pData_Type,CHARINDEX(',',@pData_Type)+1, CHARINDEX(')',@pData_Type) - CHARINDEX(',',@pData_Type) - 1)
, @TotalDigitsOfValue AS INT
, @TotalDecimalsOfValue AS INT
, @TotalWholeDigitsOfType AS INT
, @TotalWholeDigitsOfValue AS INT
SET @pExpression = REPLACE(@pExpression, ',','.')
SET @TotalDigitsOfValue = LEN(REPLACE(@pExpression, '.',''))
SET @TotalDecimalsOfValue = CASE Charindex('.', @pExpression)
WHEN 0
THEN 0
ELSE Len(Cast(Cast(Reverse(CONVERT(VARCHAR(50), @pExpression, 128)) AS FLOAT) AS BIGINT))
END
SET @TotalWholeDigitsOfType = @TotalDigitsOfType - @TotalDecimalsOfType
SET @TotalWholeDigitsOfValue = @TotalDigitsOfValue - @TotalDecimalsOfValue
-- The total digits can not be greater than the p part of NUMERIC (p, s)
-- The total of decimals can not be greater than the part s of NUMERIC (p, s)
-- The total digits of the whole part can not be greater than the subtraction between p and s
IF (@TotalDigitsOfValue <= @TotalDigitsOfType) AND (@TotalDecimalsOfValue <= @TotalDecimalsOfType) AND (@TotalWholeDigitsOfValue <= @TotalWholeDigitsOfType)
BEGIN
DECLARE @pExpressionNUMERIC AS FLOAT
SET @pExpressionNUMERIC = CAST (ROUND(@pExpression, @TotalDecimalsOfValue) AS FLOAT)
RETURN @pExpressionNUMERIC --Returns type FLOAT
END
else
BEGIN
RETURN @pReturnValueIfErrorCast
END-- FIN IF (@TotalDigitisOfValue <= @TotalDigits) AND (@TotalDecimalsOfValue <= @TotalDecimals)
END
ELSE
BEGIN
RETURN @pReturnValueIfErrorCast
END --FIN IF ISNUMERIC(@pExpression) = 1
END --IF @pData_Type LIKE 'NUMERIC%'
--------------------------------------------------------------------------------
-- BIT
--------------------------------------------------------------------------------
IF @pData_Type LIKE 'BIT'
BEGIN
IF ISNUMERIC(@pExpression) = 1
BEGIN
RETURN CAST(@pExpression AS BIT)
END
ELSE
BEGIN
RETURN @pReturnValueIfErrorCast
END --FIN IF ISNUMERIC(@pExpression) = 1
END --IF @pData_Type LIKE 'BIT'
--------------------------------------------------------------------------------
-- FLOAT
--------------------------------------------------------------------------------
IF @pData_Type LIKE 'FLOAT'
BEGIN
IF ISNUMERIC(REPLACE(REPLACE(@pExpression, CHAR(13), ''), CHAR(10), '')) = 1
BEGIN
RETURN CAST(@pExpression AS FLOAT)
END
ELSE
BEGIN
IF REPLACE(@pExpression, CHAR(13), '') = '' --Only white spaces are replaced, not new lines
BEGIN
RETURN 0
END
ELSE
BEGIN
RETURN @pReturnValueIfErrorCast
END --IF REPLACE(@pExpression, CHAR(13), '') = ''
END --FIN IF ISNUMERIC(@pExpression) = 1
END --IF @pData_Type LIKE 'FLOAT'
--------------------------------------------------------------------------------
-- Any other unsupported data type will return NULL or the value assigned by the user to @pReturnValueIfErrorCast
--------------------------------------------------------------------------------
RETURN @pReturnValueIfErrorCast
END
คำตอบของโจเซฟชี้ให้เห็นว่า ISNUMERIC ยังจัดการสัญกรณ์ทางวิทยาศาสตร์เช่น '1.3e + 3' แต่คำตอบของเขาไม่ได้จัดการกับรูปแบบของตัวเลขนี้
การโยนเงินหรือลอยตัวก่อนจัดการทั้งเรื่องสกุลเงินและประเด็นทางวิทยาศาสตร์:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TryConvertInt]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[TryConvertInt]
GO
CREATE FUNCTION dbo.TryConvertInt(@Value varchar(18))
RETURNS bigint
AS
BEGIN
DECLARE @IntValue bigint;
IF (ISNUMERIC(@Value) = 1)
IF (@Value like '%e%')
SET @IntValue = CAST(Cast(@Value as float) as bigint);
ELSE
SET @IntValue = CAST(CAST(@Value as money) as bigint);
ELSE
SET @IntValue = NULL;
RETURN @IntValue;
END
ฟังก์ชั่นจะล้มเหลวหากจำนวนมากกว่าค่า bigint
หากคุณต้องการส่งคืนค่าเริ่มต้นที่แตกต่างออกไปให้ปล่อยให้ฟังก์ชันนี้เป็นค่าทั่วไปและแทนที่ค่าว่างในภายหลัง:
SELECT IsNull(dbo.TryConvertInt('nan') , 1000);
ฉันรู้ว่ามันไม่สวย แต่มันเรียบง่าย ลองสิ่งนี้:
declare @AlpaNumber nvarchar(50) = 'ABC'
declare @MyNumber int = 0
begin Try
select @MyNumber = case when ISNUMERIC(@AlpaNumber) = 1 then cast(@AlpaNumber as int) else 0 end
End Try
Begin Catch
-- Do nothing
End Catch
if exists(select * from mytable where mynumber = @MyNumber)
Begin
print 'Found'
End
Else
Begin
print 'Not Found'
End
วิธีแก้ปัญหาของฉันคือการสร้างฟังก์ชันที่แสดงด้านล่าง ข้อกำหนดของฉันรวมถึงว่าจำนวนนั้นต้องเป็นจำนวนเต็มมาตรฐานไม่ใช่ BIGINT และฉันต้องอนุญาตให้ใช้จำนวนลบและจำนวนบวก ฉันไม่พบสถานการณ์ที่ล้มเหลว
CREATE FUNCTION [dbo].[udfIsInteger]
(
-- Add the parameters for the function here
@Value nvarchar(max)
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE @Result int = 0
-- Add the T-SQL statements to compute the return value here
DECLARE @MinValue nvarchar(11) = '-2147483648'
DECLARE @MaxValue nvarchar(10) = '2147483647'
SET @Value = ISNULL(@Value,'')
IF LEN(@Value)=0 OR
ISNUMERIC(@Value)<>1 OR
(LEFT(@Value,1)='-' AND LEN(@Value)>11) OR
(LEFT(@Value,1)='-' AND LEN(@Value)=11 AND @Value>@MinValue) OR
(LEFT(@Value,1)<>'-' AND LEN(@Value)>10) OR
(LEFT(@Value,1)<>'-' AND LEN(@Value)=10 AND @Value>@MaxValue)
GOTO FINISHED
DECLARE @cnt int = 0
WHILE @cnt<LEN(@Value)
BEGIN
SET @cnt=@cnt+1
IF SUBSTRING(@Value,@cnt,1) NOT IN ('-','0','1','2','3','4','5','6','7','8','9') GOTO FINISHED
END
SET @Result=1
FINISHED:
-- Return the result of the function
RETURN @Result
END