2

TSQL /SQLServerでVarcharをIntに「解析」するためのより良い方法があるかどうか疑問に思っています。CAST / CONVERTシステム機能よりも堅牢なものが必要なため、「解析」と言います。解析が失敗した場合、または「デフォルト」値でさえもNULLを返すと特に便利です。

これが私が現在使用している関数で、元々は誰かのSQLブログから取得したものです(具体的に誰を思い出せない)...

ALTERFUNCTION[dbo]。[udf_ToNumber]
((
    @Str varchar(max)
)。
リターンint
なので
始める
    DECLARE @Result int

    SET @Str = LTRIM(RTRIM(@Str))

    IF(@ Str ='' OR @Str IS NULL
        またはISNUMERIC(@Str)= 0
        または@StrLIKE'%[^-+ 0-9]%'
        または@StrIN('。'、'-'、'+'、'^')
        )。
        SET @Result = NULL
    そうしないと
    IF(CAST(@Str AS NUMERIC(38,0))NOT BETWEEN -2147483648。AND2147483647。)
        SET @Result = NULL
    そうしないと
        SET @Result = CAST(@Str AS int)

    @Resultを返す
終わり

(そして、「@ Resultがnullの場合、@ Result =を設定する」などのように、末尾の前に行を追加できます)。

JOINまたはWHERE-IN-SELECTで使用するため、あまり効率的ではありません。たとえば、LEFT列がINTで、RIGHTがVARCHARであり、非常に大きなデータセットでRIGHTを解析しようとすると、次のようになります。最初にLEFT(INT)列をVARCHARにキャストしてから、JOINを実行する場合よりもはるかに長くなります。

とにかく、テーブル/データ型が適切に作成および入力されていれば、そもそもこの種のことを行う必要はないことを「理想的に」知っていますが、理想的な世界は現実からかけ離れていることもありますが、だから私をユーモア。ありがとう!

編集:SQLServerバージョン2005および2008; 2005を実行しているボックスはまもなくアップグレードされるため、2008固有の回答で問題ありません。

4

1 に答える 1

2

私の経験では、スカラー UDF は大規模なデータ セットではうまく機能しません。回避策として、次の 2 つのオプションのいずれかを試すことができます (どちらも特にうまく機能するかどうかはわかりません)。

  1. 次のように、結合自体に関数のロジックを埋め込みます。

    SELECT columnlist
    FROM a JOIN b ON a.INT = (SELECT  CASE WHEN ( b.varchar= ''
                        OR b.varchar IS NULL
                        OR ISNUMERIC(b.varchar) = 0
                        OR b.varchar LIKE '%[^-+ 0-9]%'
                        OR b.varchar IN ( '.', '-', '+', '^' )
                      ) THEN NULL
                 WHEN CAST(b.varchar AS NUMERIC(38, 0)) NOT BETWEEN -2147483648.
                                                   AND         2147483647.
                 THEN NULL
                 ELSE CAST (b.varchar AS INT)
            END)
    
  2. ユーザー定義関数をインライン テーブル値関数に変更し、CROSS APPLY 構文を使用します。

    CREATE FUNCTION udf_ToInt
    (   
        @str VARCHAR(MAX)
    )
    RETURNS TABLE 
    AS
    RETURN 
    (
        SELECT  CASE WHEN ( @Str = ''
                        OR @Str IS NULL
                        OR ISNUMERIC(@Str) = 0
                        OR @Str LIKE '%[^-+ 0-9]%'
                        OR @Str IN ( '.', '-', '+', '^' )
                      ) THEN NULL
                 WHEN CAST(@Str AS NUMERIC(38, 0)) NOT BETWEEN -2147483648.
                                                   AND         2147483647.
                 THEN NULL
                 ELSE CAST (@Str AS INT) as IntVal
            END           
    
    )
    GO
    
    SELECT columnlist
    FROM b
    CROSS APPLY udf_ToInt(b.varchar) t
    JOIN a ON t.IntVal = a.Int
    

おそらく VARCHAR に変換して比較する方が簡単です:)

于 2012-06-21T17:40:57.423 に答える