2012-05-22 12 views
9

これは適切ではないが、本当にこれは「方法」ではなく「理由」です。それが適切であるかどうかわからないが、より良い場所を尋ねることを知らないし、私が探しているものを得るためにどのようにフレーズをGoogleに考えることができない。IF節のSQL評価

IF 'hell' = 'freezing over' 
    BEGIN 
    SELECT log(0) 
    END 

この声明を見てください。 IF句が真となる世界はありません。私がそれを実行しようとすると、私はSQLがIF節を越えてジャンプし、最後に移動することを期待しています。代わりに私は得る:

An invalid floating point operation occurred. 

これは奇妙です。だから私はそれがSQLがそれをする方法であると思います。例外...

IF 'hell' = 'freezing over' 
    BEGIN 
    SELECT 1/0 
    END 

エラーはありません。 IF句のステートメントはエラーを生成するはずです。なぜこれが起こっていないのか誰も説明できますか?

これは、EXP節(SUM(LOG()))がif節内のデータを蓄積するために使用される大量のSQL計算をデバッグする際に発生しました。それをやめるためにコードを変更することはできますが、IF句内で何かが評価されていないのはなぜですか。

乾杯。

EDIT:追加の娯楽。キャッチしてみる? Pffft

IF 1=2 
    BEGIN 
     BEGIN TRY 
      SELECT SQRT(-1) 
     END TRY 
     BEGIN CATCH 
     END CATCH 
    END 

非数学:

IF 1=2 
    BEGIN 
    SELECT SUBSTRING('hello',-1,-1) 
    END 

答えて

7

私の推測がlog(0)が効果的に早期に評価されることであろう1/0一方に起因するconstant-foldingではない、いずれかの基数推定またはANSI_WARNINGS設定がゼロ(オーバーフローVSによって除算の所望の結果に影響を与える可能性が高いことに起因ヌル)。

+0

ANSIの警告は違いはありませんでしたが、それは私がとても感謝する必要があると思うリンクです:) –

+0

あなたの歓迎。 ANSI_WARNINGS私は、 "set ansi_warnings off"がいつでも発行された場合、ゼロによる除算エラーが表示されないことを意味しました。コンパイラは、コンパイルされたクエリが実行されるときにANSI_WARNINGSフラグの状態を事前に知ることができないため、コンパイル時にゼロ除算例外を発生させる折り畳まれた式は無視しなければなりません。 (ansi_warningsが常にオフになることが保証されていれば、1/0はNULLになります) –

2

パーサは単にあなたのIFロジックをフォローする知性を持っていません。パーサはバッチ内CREATE TABLE文の全てを見て、あなたが二回表を作成しようとしたと判断し、あなたはそれを解析しても、それを実行するかどうか

IF (1 = 0) 
BEGIN 
    CREATE TABLE #t(x INT): 
END 
ELSE 
BEGIN 
    CREATE TABLE #t(x INT): 
END 

(最初のコピー明らかにdoesnの次の例を考えてみましょうこれが起こるために存在しなければならない)。結果:

メッセージ2714、レベル16、状態1、行7
がデータベースに '#tを' という名前のオブジェクトが既に存在します。

パーサーがあなたほどスマートではないよりも、私があなたのためにより良い答えを持っているかどうかはわかりません。

実行時まで動的SQLを使用して問題を延期することで、パーサーを無効にすることができます。

IF 'hell' = 'freezing over' 
BEGIN 
    EXEC sp_executesql N'SELECT log(0);'; 
END 

しかし、私は本当のことはありません条件のための足場を設定すると、エラーに起こっている知っている文を発行するポイントが何であるか、疑問に思う必要があるだろうか?

+0

約5つのIF条件があります。そのうちの1つでは、他の条件でエラーが発生するデータに対して計算が行われます。 これらの例は、動作を示すのは簡単です。 IF [データはエラーを起こさない] "計算する" END –

+0

また、興味深いことに、それはうまく解析されるが、正常に実行されない –

+0

はい、パーサーは、実行時にエラーになることはありません事前にいくつかをキャッチします。私が言ったように、それは賢明ではない。しかし、それは複雑なルールとアルゴリズムの*たくさんの*を持っているので、何がうまく解析されるのか、それができないのかが決まります。これらのルールは文書化されていないので、@ GordonLinoffはどのような種類のものがパーサーを飛び越えるのか、どのようなものをスライドさせるのかを知っておく必要があると説明しました。 –

0

明らかに、SQLコンパイラが実行時とコンパイル時に評価しようとしている表現がいくつかあります。私の推測では、部門はあまりにも高価ではないと考えられているので、実行時にそれを延期します。一方、log()のように実際に複雑なものは高価で、コンパイル時にやりたいものです。

これは推測です。また、そのような違いは非決定的であることを意味します。特定のスクリプトでどのスクリプトが動作するのか、それとも動作しないのかを把握しておく必要があります。また、その動作はデータベースのリリース間で変更される可能性があります。

2

私はSQLのIF句を飛び越すと末尾に移動するために期待してい実行それにしようとした場合。

あなたのバッチを実行すると三つのことは、あなたのSQLが解析される

  1. 起こる

    あなたのSQLがコンパイルされ
  2. あなたのSQLが実行され

unfoのものrtunateは、SQLサーバーのバッチ内のコンパイルエラーと実行エラーの両方が、同じ「Query Completed with errors」というメッセージになることです。だから、その簡単には違い

は手順がうまく解析する以下の

Create proc compiletime 
as 
SELECT log(0) 
SELECT SQRT(-1) 
SELECT SUBSTRING('hello',-1,-1) 
SELECT 1/0 

を考えてみましょう見るために手順を使用することができます。ただし、パラメータとして無効な定数がいくつかあるため、最初のSELECTを削除しない限りコンパイルできません。 SELECT 1/0でも実行時エラーではなくコンパイル時エラーが発生しますが、@Alex KはANSI_WARNINGSに基づいているため、コンパイル時エラーではないことを示しています。

だからこそ、私たちは最初の2つの違いが分かりました。また、コンパイル時エラーのためにTRY CATCHが機能しなかった理由についても説明します。

なぜSQLサーバーは到達不能なコードをコンパイルするのですか? 一般にに到達できないことを知るためには、停止問題の解決策が必要です。あなたはいくつかのケースのためにそれを解決したが、このことができます...


DECLARE @x as integer 
SET @x = SomeFunction() 
If (1 = @x) 
    SomeCompiletime error 

はさらに混乱で異なる動作をする必要があります。

if (1=0) 
    SomeCompiletime error