11

私は SQL に精通していますが、SQL ジオメトリ機能を使用するのは初めてです。おそらく解決すべき非常に基本的な問題がありますが、ジオメトリ オブジェクトの使用方法を説明する適切なリソースがオンラインで見つかりませんでした。(Technet は、新しいことを学ぶにはお粗末な方法です...)

デカルト平面上に 2 次元の点のコレクションがあり、半径のコレクション内にあるすべての点を見つけようとしています。

次のような構文を使用してテーブルを作成し、データを入力しました。

Update [Things] set [Location] = geometry::Point(@X, @Y, 0)

(@X、@Y は単なる x 値と y 値です。0 はすべてのオブジェクトで共有される任意の数値であり、正しく理解すればフィルタリングを設定できます)

ここで私はレールから外れます...ある種のポリゴンコレクションとそれを使用してクエリを構築しようとしますか、それとも円形ポリゴンの束を構築せずに複数の半径の交差をチェックする簡単な方法はありますか?

補遺: 複数の半径の質問に対する答えを誰も持っていない場合、単一の半径の解決策は何ですか?

アップデート

以下は、星が xy グリッド上にポイントとして保存されている架空の星データベースを使用して、私が作成したいくつかの例です。

ボックス内のすべてのポイントを選択します。

DECLARE @polygon geometry = geometry::STGeomFromText('POLYGON((' 
+ CAST(@MinX AS VARCHAR(10)) + ' '  + CAST(@MinY AS VARCHAR(10)) + ',' 
+ CAST(@MaxX AS VARCHAR(10)) + ' '  + CAST(@MinY AS VARCHAR(10)) + ', ' 
+ CAST(@MaxX AS VARCHAR(10)) + ' '  + CAST(@MaxY AS VARCHAR(10)) + ',' 
+ CAST(@MinX AS VARCHAR(10)) + ' '  + CAST(@MaxY AS VARCHAR(10)) + ',' 
+ CAST(@MinX AS VARCHAR(10)) + ' '  + CAST(@MinY AS VARCHAR(10)) + '))', 0);

SELECT  [Star].[Name]           AS [StarName],
        [Star].[StarTypeId]     AS [StarTypeId],        
FROM    [Star]
WHERE   @polygon.STContains([Star].[Location]) = 1

これをパターンとして使用すると、複数のポリゴンを定義するなど、あらゆる種類の興味深いことができます。

WHERE   @polygon1.STContains([Star].[Location]) = 1
OR @polygon2.STContains([Star].[Location]) = 1
OR @polygon3.STContains([Star].[Location]) = 1

または距離を確認する:

WHERE [Star].[Location].STDistance(@polygon1) < @SomeDistance 

挿入ステートメントの例

INSERT [Star]
(
    [Name],
    [StarTypeId],
    [Location],
)
VALUES
(
    @Name,
    @StarTypeId,
    GEOMETRY::Point(@LocationX, @LocationY, 0),
)
4

2 に答える 2

18

これは信じられないほど遅い答えですが、おそらく解決策に光を当てることができます. 参照する「セット」番号は、空間参照識別子または SRID です。緯度/経度の計算では、これを 4326 に設定することを検討する必要があります。これにより、メートルが測定単位として確実に使用されます。SqlGeometry ではなく SqlGeography に切り替えることも検討する必要がありますが、ここでは SqlGeometry を続行します。SRID を一括設定するには、次のようにテーブルを更新します。

UPDATE [YourTable] SET [SpatialColumn] = GEOMETRY.STPointFromText([SpatialColumn].STAsText(), 4326);

半径が 1 つの場合は、半径を空間オブジェクトとして作成する必要があります。例えば:

DECLARE @radiusInMeters FLOAT = 1000; -- Set to a number in meters
DECLARE @radius GEOMETRY = GEOMETRY::Point(@x, @y, 4326).STBuffer(@radiusInMeters);

STBuffer() は空間ポイントを取得し、そこから円 (現在は Polygon タイプ) を作成します。次に、次のようにデータセットをクエリできます。

SELECT * FROM [YourTable] WHERE [SpatialColumn].STIntersects(@radius);

上記は、クエリ プランの [SpatialColumn] で作成した空間インデックスを使用します。

また、機能する (さらに空間インデックスを使用する) 単純なオプションもあります。STDistance メソッドを使用すると、次のことができます。

DECLARE @radius GEOMETRY = GEOMETRY::Point(@x, @y, 4326);
DECLARE @distance FLOAT = 1000; -- A distance in metres   
SELECT * FROM [YourTable] WHERE [SpatialColumn].STDistance(@radius) <= @distance;

最後に、半径のコレクションを操作します。いくつかのオプションがあります。1つ目は、上記を半径ごとに順番に実行することですが、次のことを1つとして実行することを検討します。

DECLARE #radiiCollection TABLE
(
    [RadiusInMetres] FLOAT,
    [Radius] GEOMETRY
)

INSERT INTO #radiiCollection ([RadiusInMetres], [Radius]) VALUES (1000, GEOMETRY::Point(@xValue, @yValue, 4326).STBuffer(1000));
-- Repeat for other radii

SELECT
    X.[Id],
    MIN(R.[RadiusInMetres]) AS [WithinRadiusDistance]
FROM
    [YourTable] X
    JOIN
    #radiiCollection RC ON RC.[Radius].STIntersects(X.[SpatialColumn])
GROUP BY
    X.[IdColumn],
    R.[RadiusInMetres]

DROP TABLE @radiiCollection;

上記の最終版はテストされていませんが、わずかな微調整が可能であり、ほぼそこにあると 99% 確信しています。選択で最小半径距離を取得する理想は、複数の半径が単一の場所に由来する場合、ポイントが最初の半径内にある場合、それは自然に他のすべての半径内にあるということです。したがって、レコードを複製しますが、グループ化して最小値を選択すると、1 つだけ (最も近いもの) が得られます。

質問してから4週間経ちますが、お役に立てば幸いです。質問用の空間タグが 1 つだけだったら、もっと早く見れなかったのに残念です!!!!

于 2014-03-09T22:31:56.257 に答える
-1

もちろん、これは可能です。個々の where 句は次のようになります。

DIM @Center AS Location
-- Initialize the location here, you probably know better how to do that than I.
Dim @Radius AS Decimal(10, 2)
SELECT * from pointTable WHERE sqrt(square(@Center.STX-Location.STX)+square(@Center.STX-Location.STX)) > @Radius 

次に、一連の半径と xy ポイントを次のようなテーブル変数に積み上げることができます。

Dim @MyCircleTable AS Table(Geometry Circle) 
INSERT INTO @MyCircleTable (.........)

注: これをコンパイラに通したわけではありませんが、これは実用的なソリューションの骨子です。

他のオプションはここにあるようです: http://technet.microsoft.com/en-us/library/bb933904.aspx

そして、一見動作する構文のデモがここにあります : stwithin-?forum=sqlspatial

2 番目の投稿は、次の構文を意味します。

SELECT Distinct pointTable.* from pointTable pt, circletable crcs
WHERE crcs.geom.STContains(b.Location) = 1
于 2014-02-11T17:20:01.780 に答える