私はこのエラーを受け取りました:
'geography::Point' failed because parameter 1 is not allowed to be null.
このSQLでは:
SELECT [ID], geography::Point([lat], [long], 4326) AS [loc]
FROM (
SELECT [ID], CONVERT(float, [lat]) AS [lat], CONVERT(float, [long]) AS [long]
FROM (
SELECT [ID], [lat],
[long], ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY [EFFDT] desc) AS [sequence]
FROM [GEO]
) AS temp1
WHERE [sequence] = 1
AND [lat] IS NOT NULL
AND [long] IS NOT NULL
) AS temp2
ORDER BY [ID]
しかし、そこにはnull値はなく、私たちの開発マシン(Dev 13.0.1728.2)ではなく、本番マシン(Production 13.0.4422.0)でのみエラーが発生していました。何時間も検索して再試行した後、いくつかのものを並べ替えることでこれが機能することがわかりました:
SELECT [ID], [loc]
FROM (
SELECT [ID],
geography::Point([lat], [long], 4326) AS [loc],
,ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY [EFFDT] desc) AS [sequence]
FROM [GEO]
WHERE [lat] IS NOT NULL
AND [long] IS NOT NULL
) AS temp
WHERE [sequence] = 1
最初のクエリで何が間違っていたのか、なぜこれが2番目のクエリで機能したのかを理解したいのですが?
最初のクエリでは、発効日列を使用して計算されたシーケンス番号に基づいて最新のレコードを持つ行のみを取得し、緯度と経度のデータを地理タイプに変換しようとしました。
2番目のクエリでは、緯度と経度のデータを変換してからフィルタリングします。
最初のクエリの方が効率的だと思いました。
以前に、GeometryおよびGeographyデータ型で同様の問題に遭遇しました。問題は、オプティマイザが計画内のジオメトリを構築することを決定する場所(および方法)に関係していると思います。
私は基本的に挿入ステートメントで問題がありました
INSERT INTO (ID,GEOM)
SELECT ID, Geometry::Point(ISNULL(X,0),ISNULL(Y,0),0)
FROM HeapTable
WHERE X is not NULL and Y is not NULL
遊んで少し混乱した後、
INSERT INTO (ID,GEOM)
SELECT ID, Geometry::Point(ISNULL(X,0),ISNULL(Y,0),0)
FROM HeapTable;
INSERT INTO (ID,GEOM)
SELECT ID, Geometry::Point(ISNULL(X,0),ISNULL(Y,0),0)
FROM HeapTable
WHERE ISNULL(X,0) != 0;
どちらも機能しますが、以下は機能しません
INSERT INTO (ID,GEOM)
SELECT ID, Geometry::Point(X,Y,0)
FROM HeapTable
WHERE ISNULL(X,0) != 0;
最初のクエリの場合、計画は、計算スカラーがフィルターの前に実行されることを示しています
そして、計算されている式からISNULL
関数が取り除かれています。
<ColumnReference Column="Expr1005" />
<ScalarOperator ScalarString="[Geometry]::Point(CONVERT_IMPLICIT(float(53),[sandbox].[dbo].[TestNullGeomIssueSource].[X],0),CONVERT_IMPLICIT(float(53),[sandbox].[dbo].[TestNullGeomIssueSource].[Y],0),(0))">
ジオメトリと地理上のポイントには、NULLを入力できないという欠陥があると思います。結果として、NULLを返すだけのほうが正しいと思います。
必要に応じて、このためのテストスクリプト全体を用意できます。
クエリの最後に次のものと同等のものを追加することで、クエリがエラーをスローしないようにすることができました。
WHERE Id IN (
SELECT Id FROM [Geo]
WHERE [lat] IS NOT NULL AND [long] IS NOT NULL
)