2017-08-04 3 views
2

where句で特定の条件を無効または有効にすると、選択クエリが.NET Frameworkエラーをスローするという奇妙な問題に直面しています。SQLクエリでwhere句を有効にすると.NET Frameworkエラーが発生する

ここにはCREATEテーブルスクリプトがあります。

test_classes

CREATE TABLE [dbo].[test_classes] 
(
    [CLASSID] [int] NOT NULL, 
    [PARENTID] [int] NULL, 
    [CATID] [int] NOT NULL, 
    [CLASS_NAME] [nvarchar](255) NOT NULL, 
    [ORIGINAL_NAME] [nvarchar](255) NULL, 
    [GEOMETRY] [tinyint] NOT NULL, 
    [READ_ONLY] [bit] NOT NULL, 
    [DISPLAY_STYLES] [image] NULL, 
    [FEATURE_COUNT] [int] NOT NULL, 
    [TEMPOWNER] [int] NULL, 
    [OPTIONS] [int] NOT NULL, 
    [POLYGON_TYPE] [int] NULL, 
    [CLASS_EXTRA] [nvarchar](1024) NULL, 
    [MAPID] [int] NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

test_polygon

CREATE TABLE [dbo].[test_polygon] 
(
    [FID] [nvarchar](36) NOT NULL, 
    [EXTENT_L] [float] NOT NULL, 
    [EXTENT_T] [float] NOT NULL, 
    [EXTENT_R] [float] NOT NULL, 
    [EXTENT_B] [float] NOT NULL, 
    [COORDINATES] [image] NULL, 
    [CHAINS] [smallint] NOT NULL, 
    [CLASSID] [int] NOT NULL, 
    [SPATIAL_KEY] [bigint] NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

により(による画像データ型に)ワード制限は、ここでINSERT入力される:GDrive SQL Link

SELECT SQLクエリ:

select 
    Class_Name, FID, 
    geometry::STGeomFromWKB(b1+b2,0) as polygon, 
    Class_ID, Original_Name 
from 
    (Select 
     cl.Class_Name, p.FID, 
     substring(CAST(p.Coordinates AS varbinary(max)),1,1) as b1, 
     substring(CAST(p.Coordinates AS varbinary(max)),3,999999) as b2, 
     cl.ClassID as Class_ID, 
     cl.Original_Name 
    From  
     test_polygon p 
    Inner Join 
     test_classes cl on cl.ClassID = p.ClassID) s_polygon 
--where Class_ID = 215     --Filter#1 
--where Class_Name = 'L1_County'  --Filter#2 

注意すると、Class_ID 215は 'L1_County' class_nameを表します。

問題は、フィルタ#1を有効にすると、出力が期待どおりであることです。しかし、フィルタ#2だけを有効にすると、クエリは.NET Errorで失敗します。

予想される出力:私が得る

Class_Name FID    polygon  Class_ID Original_Name 
----------- ---------------- ------------- ----------- ------------------------ 
L1_County Northamptonshire <long value> 215   B8USR_4DB8184E88092424 

エラー:

6522、レベル16、状態1、行4
A .NET Frameworkのエラーは、ユーザー定義ルーチンの実行中に発生しました
System.FormatException:24119:外部リングの開始点と終了点が同じではないため、ポリゴン入力が無効です。ポリゴンの各リングは、同じ開始点と終了点を持つ必要があります。

にSystem.FormatException:Microsoft.SqlServer.Types.Validatorで
Microsoft.SqlServer.Types.GeometryValidator.ValidatePolygonRingで (のInt32 iRing、のInt32 cPoints、ダブルfirstX、ダブルfirstY、ダブルlastX、ダブルlastY)
。実行(遷移遷移)Microsoft.SqlServer.Types.ForwardingGeoDataSink.EndFigure()で
Microsoft.SqlServer.Types.WellKnownBinaryReader.ReadLineStringPoints(BYTEORDER BYTEORDER、UInt32型cPoints、ブールREADZ、ブールreadM)
Microsoft.SqlServer ATで
.Types.WellKnownBinaryReader.ReadLinearRing(ByteOrder byteOrder、Boolean readZ、Boolean readM)Microsoft.SqlServer.Types.WellKnownBinaryReader.ReadでMicrosoft.SqlServer.Types.WellKnownBinaryReader.ParseWkbPolygonWithoutHeader(BYTEORDER BYTEORDER、ブールREADZ、ブールreadM)Microsoft.SqlServer.Types.WellKnownBinaryReader.ParseWkbで
(OpenGisType>型)>で (OpenGisType型、Int32 srid)
、Microsoft.SqlServer.Types.SqlGeometry.GeometryFromBinary(OpenGisType型、SqlBytesバイナリ、Int32 srid)

WHERE句にClass_Nameがあり、Class_IDでないときにエラーが発生するのはなぜですか。

私はSQL Server 2012 Enterprise Editionを使用しています。エラーはSQL Server 2008でも複製されます。

編集

plan1

フィルタ#2の推定実行計画:フィルタ#1のための

推定実行計画

plan2

+2

これは可能性があるため、異なる実行計画へ。 IDフィルタは索引を使用する可能性が高いため、索引に基づいて1つの行のみが戻されます。名前フィルタは表スキャンを使用していて、多くの行(「dodgy行」を含む)を戻してからジオメトリを計算し、 – Alex

+0

ちょうどそれを詳しく説明するにはおそらくこの質問に似ています:https://stackoverflow.com/questions/17427560/conversion-failed-when-converting-the-varchar-value-n-to-data-type-in​​t。フィルタなしでクエリを実行するとエラーが発生しますか? – Alex

+0

コメントありがとう@Alex。はい、フィルタなしで実行するとエラーが発生します。それは当然です。 1つの特定のポリゴンに対してWKBが失敗します。私の質問は、なぜフィルタ#2は、フィルタ#1のようなレコードをフィルタリングしていないということでした。 –

答えて

2

私はコメントを要約します:

テーブルに無効なデータが含まれているため、この問題が発生しています。 test_polygon.Class_IDで検索するときに表示されない理由は、Class_IDが表スキャンの述部として渡されることです。フィルターとしてtest_classes.Class_Nameを使用すると、検索述部はtest_classesテーブルに適用されます。 geometry::STGeomFromWKB "Compute Scalar"は "Join"の前に発生し、test_polygonのすべての行が無効なデータを含む行を含めてこの関数によって評価されます。

更新:計画は同じように見えるにもかかわらず、述語条件が異なるフィルタ(WHERE条件)のために異なっているので、テーブルスキャンオペレータの出力が異なっているよう、彼らは、ありません。

これは、想定されていない設計によるSQL Serverクエリの評価の順序を強制的に行う標準的な方法ではありません。

  1. マテリアライズ(表に格納)サブクエリの結果:

    2つのオプションがあります。これは、単純に、問合せを2つの別々の問合せ(レコードを検索するクエリと2つ目のクエリ)に分割して、検索結果のデータを計算します。中間結果は(一時)テーブルに格納されます。

  2. "ハッキング"を使用すると、SQL Serverを強制的にクエリを評価することができます。

    select 
        Class_Name, FID, 
        CASE WHEN Class_Name = Class_Name THEN geometry::STGeomFromWKB(b1+b2,0) ELSE NULL END as polygon, 
        Class_ID, Original_Name 
    from 
        (Select 
         cl.Class_Name, p.FID, 
         substring(CAST(p.Coordinates AS varbinary(max)),1,1) as b1, 
         substring(CAST(p.Coordinates AS varbinary(max)),3,999999) as b2, 
         cl.ClassID as Class_ID, 
         cl.Original_Name 
        From  
         test_polygon p 
        Inner Join 
         test_classes cl on cl.ClassID = p.ClassID) s_polygon 
    --where Class_ID = 215     --Filter#1 
    where Class_Name = 'L1_County'  --Filter#2 
    

    JOINが解決された後、我々はそれを評価するために、SQL Serverを強制されているtest_classes.Class_Name見ダミーCASE式を追加することにより:

は、以下の「ハッキング」の一例です。

計画:

New Plan

有用な製品: http://sqlblog.com/blogs/adam_machanic/archive/2006/10/03/exploring-the-secrets-of-intermediate-materialization.aspx

+0

'Class_IDが述語として渡されるのはなぜですか?それは 'int'なので?別のオプションは、サブクエリを最初に実現することです。 –

+0

@VojtěchDohnal - 最初の質問が何を意味するのかよくわかりません。述語はWHERE句に現れるフィルタです。 'Class_Name'で検索すると、' test_classes'の述語に追加されます。データ型とは関係ありません。 RE:最初にサブクエリをマテリアライズする - はい、一時テーブルに結果を保存することができます。これを指摘してくれてありがとう、私は私の答えを更新します。 – Alex

+0

あなたのおかげです。誰かが説明するより良い理由がない限り、私はかなり満足しています。 :-) –

関連する問題