5

私はこのような見方をしています:

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode
FROM   dbo.asset
WHERE  (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')

私がこのように呼ぶと、それは機能します:

SELECT * FROM FooView

ただし、WHERE句を追加すると、次のようになります。

SELECT * FROM FooView WHERE ProcessCode > 0

このエラーが発生します:

varchar値'-01-'をデータ型intに変換するときに変換に失敗しました。

なんで?場所はの形式1-2-100-0800-Aである必要があるため、変換エラーがどのように発生するかわかりません。結果をフィルタリングするCAST前に失敗する可能性はありますか?WHEREもしそうなら、なぜ最初のクエリが機能するのですか?

編集-回避策

同僚に良い回避策を提案してもらいました。それは機能しますが、それでも最初の問題の理由を説明していません。

これは、ProcessCodeのSELECTにあります。

CASE WHEN location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_'
THEN CAST(SUBSTRING(location, 9, 4) AS int) ELSE 0 END AS ProcessCode, 
4

3 に答える 3

4

これにあなたの見方を変えてください

SELECT location,
       CASE WHEN SUBSTRING(location, 9, 4) > ''
             AND SUBSTRING(location, 9, 4) NOT LIKE '%[^0-9]%' THEN
                 CAST(SUBSTRING(location, 9, 4) AS int) END AS ProcessCode
  FROM dbo.asset
 WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
   AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')

この接続アイテムを参照してください

SQL Serverは、最適化されていると判断した順序でWHERE/SELECT句を自由に評価できます。INDEXED VIEWとして具体化されていない限り、ビューは外部クエリに展開されるため、WHERE句は実際にビューに合理化されます。

SELECT * FROM FooView WHERE ProcessCode > 0
 -- is really seen as
SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode
FROM   dbo.asset
WHERE  (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')
AND CAST(SUBSTRING(location, 9, 4) AS int) > 0 ---- << Expanded inline

式はSELECT句とWHERE句の両方に使用されるため、SQL Serverは、元の取得で最初にSELECT句の式を解決することを決定したようです。これは、Ctrl-Lを使用してクエリ実行プランを表示することで簡単に確認できます。SQL Serverがテーブルから1回の取得を行い、2つの式を同時に取得していることがわかりlocationますCAST(SUBSTRING(location, 9, 4) AS int)

于 2012-11-01T18:29:07.667 に答える
1

これはSQLServer2008で機能し、他のファンキーなことが起こっています...

create view myview
AS
SELECT  CAST(SUBSTRING('1-2-100-0800-A', 9, 4) AS int) as ProcessCode
Where '1-2-100-0800-A' LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_'

GO

SELECT * FROM myview WHERE ProcessCode > 0

これがフィドルです> http://sqlfiddle.com/#!3/3bcfd/2

編集は、以下に提案されているように実行の順序である可能性があります、in(idsで最適化)で試してください

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode
FROM   dbo.asset 
Where id in(
 select id
 from dbo.asset 
 WHERE  (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
 AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')
)
于 2012-11-01T18:13:05.653 に答える
0

はい、キャストはどこの前で失敗します。確かに、キャストはSELECT自体の前で失敗しています。私が間違っていなければ、テーブルを見て、ロケーション列の下のサブストリングの形状を決定した直後です。

返される部分文字列が何であるかについて誤算しているようです。形式が実際に1-2-100-0800-Aであると言うと、SUBSTRING(str、9、4)は0800を返すはずですが、返されます。 '-1-'、これはINTではありません。

あなたの声明をより小さなものに分析してください。最初にSUBSTRINGの結果を調べます。

それがお役に立てば幸いです。

于 2012-11-01T17:22:56.333 に答える