7

データベースで見つけたばかりのクエリがあり、レポートが失敗する原因となっています。クエリの基本的な要点:

Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
And Convert(int, myField) Between @StartRange And @EndRange

現在、myField はすべての行に数値データを含んでいるわけではありません [nvarchar 型です]... しかし、このクエリは明らかに、このフィールドのデータが数値である行のみを考慮するように設計されています。

これに関する問題は、T-SQL (私が理解している限り) が Where 句を短絡しないため、例外を除いてデータが数値ではないレコードを破棄することです:

Msg 245, Level 16, State 1, Line 1 Conversion failed when converting the nvarchar value '/A' to data type int.

myField が数値であるすべての行を一時テーブルにダンプしてから、フィールドが指定された範囲内にある行を照会する以外に、何が最適でしょうか?

返されたデータを分析し、何が起こっているのかを確認するための純粋な私の最初の解析は次のとおりです。

Select *
From (
   Select *
   From table
   Where IsNull(myField, '') <> ''
   And IsNumeric(myField) = 1
) t0
Where Convert(int, myField) Between @StartRange And @EndRange

しかし、最初のクエリで行ったのと同じエラーが発生しますが、この時点では数値であってはならないデータを変換していないため、理解できません。サブクエリは、myField に数値データが含まれる行のみを返す必要があります。

朝のお茶が必要かもしれませんが、これは誰にとっても意味がありますか? 別の目のセットが役立ちます。

前もって感謝します

4

4 に答える 4

6

IsNumericは、文字列をSQLServerの数値タイプの1つに変換できることを通知するだけです。お金や浮動小数点数に変換できる場合もありますが、整数に変換できない場合があります。

あなたの

IsNumeric(myField) = 1

することが:

not myField like '%[^0-9]%' and LEN(myField) < 9

(つまり、myFieldに数字のみを含め、intに収める必要があります)

例の編集

select ISNUMERIC('.'),ISNUMERIC('£'),ISNUMERIC('1d9')

結果:

----------- ----------- -----------
1           1           1

(1 row(s) affected)
于 2010-09-21T13:03:07.060 に答える
3

SQL に特定の順序で式を評価させる必要があります。ここに1つの解決策があります

Select *
From ( TOP 2000000000
   Select *
   From table
   Where IsNumeric(myField) = 1
   And IsNull(myField, '') <> ''
   ORDER BY Key
) t0
Where Convert(int, myField) Between @StartRange And @EndRange

そしてもう一つ

Select *
From table
Where

CASE
   WHEN IsNumeric(myField) = 1 And IsNull(myField, '') <> ''
   THEN Convert(int, myField) ELSE @StartRange-1
END Between @StartRange And @EndRange
  • 最初の手法は「中間マテリアライゼーション」です。これは、作業テーブルでソートを強制します。
  • 2番目はCASE ORDER評価に依存することが保証されています
  • どちらもきれいでも気まぐれでもない

SQL は宣言型です。オプティマイザに、実行方法ではなく、必要なものを伝えます。上記のトリックは、物事を特定の順序で実行することを強制します。

于 2010-09-21T12:49:30.073 に答える
1

これが役立つかどうかはわかりませんが、CONVERT を使用した不適切な変換は常に SQL でエラーを生成することをどこかで読みました。したがって、すべての行で CONVERT を実行することを避けるために、where 句で CASE を使用する方がよいと思います。

于 2010-09-21T12:50:05.483 に答える
1

CASEステートメントを使用します。

declare @StartRange int
declare @EndRange int

set @StartRange = 1
set @EndRange = 3

select *
from TestData
WHERE Case WHEN ISNUMERIC(Value) = 0 THEN 0
            WHEN Value IS NULL THEN 0
            WHEN Value = '' THEN 0
            WHEN CONVERT(int, Value) BETWEEN @StartRange AND @EndRange THEN 1
            END = 1
于 2010-09-21T12:51:06.687 に答える