2016-01-23 29 views
1

我想從源表創建一個目標表,它只包含唯一/不同的點,因爲在彼此相距1000米半徑範圍內應該沒有點。插入緩衝的GEOGRAPHY將點放入目標表中,不需要重複

這是(使用簡化的實體模型臨時表)的起點:

IF OBJECT_ID('tempdb..#Source') IS NOT NULL DROP TABLE #Source 
IF OBJECT_ID('tempdb..#TargetSeeded') IS NOT NULL DROP TABLE #TargetSeeded 
IF OBJECT_ID('tempdb..#TargetEmpty') IS NOT NULL DROP TABLE #TargetEmpty 

CREATE TABLE #Source 
(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    Point GEOGRAPHY 
) 

CREATE TABLE #TargetSeeded 
(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    Point GEOGRAPHY 
) 

CREATE TABLE #TargetEmpty 
(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    Point GEOGRAPHY 
) 

DECLARE @Point1 GEOGRAPHY; 
DECLARE @Point2 GEOGRAPHY; 
DECLARE @Point3 GEOGRAPHY; 
DECLARE @Point4 GEOGRAPHY; 
DECLARE @PointBufferDistanceInMeters INT; 

SET @Point1 = GEOGRAPHY::STPointFromText('POINT(1 52.50)', 4326); 
SET @Point2 = GEOGRAPHY::STPointFromText('POINT(1 52.51)', 4326); 
SET @Point3 = GEOGRAPHY::STPointFromText('POINT(1 52.52)', 4326); 
SET @Point4 = GEOGRAPHY::STPointFromText('POINT(1 52.52)', 4326); 
SET @PointBufferDistanceInMeters = 1000; 

--SELECT @Point1.STDistance(@Point2); 
--SELECT @Point1.STDistance(@Point3); 
--SELECT @Point1.STDistance(@Point4); 
--SELECT @Point2.STDistance(@Point3); 

INSERT INTO #Source 
    SELECT @Point1 
     UNION ALL 
    SELECT @Point2 
     UNION ALL 
    SELECT @Point3 
     UNION ALL 
    SELECT @Point4 

INSERT INTO #TargetSeeded 
    SELECT @Point1 
     UNION ALL 
    SELECT @Point2 

CREATE SPATIAL INDEX SpatialIndex ON #Source([Point]); 
CREATE SPATIAL INDEX SpatialIndex ON #TargetEmpty([Point]); 
CREATE SPATIAL INDEX SpatialIndex ON #TargetSeeded([Point]); 

-- Identify Ids to be inserted 
SELECT 
    Id, 
    Point 
FROM #Source WHERE Id NOT IN 
(
    SELECT 
     So.Id 
    FROM #Source AS So 
    INNER JOIN #TargetSeeded AS Ta 
    ON So.Point.STDistance(Ta.Point) < @PointBufferDistanceInMeters 
) 

我可以識別候選能夠從#Source插入作爲在(IMHO)組爲基礎的方法有效的方式(?)。我只是不知道如何刪除#Source表中的重複項(在上述意義上重複 - 具有1000米的緩衝區)。所以最終,我想將id 3或4插入#TargetSeeded(哪一個不重要)。有任何想法嗎?

PS:

這是一個相關子查詢的企圖可能是一個解決辦法:

IF OBJECT_ID('tempdb..#Source') IS NOT NULL DROP TABLE #Source 
IF OBJECT_ID('tempdb..#TargetSeeded') IS NOT NULL DROP TABLE #TargetSeeded 
IF OBJECT_ID('tempdb..#TargetEmpty') IS NOT NULL DROP TABLE #TargetEmpty 

CREATE TABLE #Source 
(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    Point GEOGRAPHY 
) 

CREATE TABLE #TargetSeeded 
(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    Point GEOGRAPHY 
) 

CREATE TABLE #TargetEmpty 
(
    Id INT IDENTITY(1,1) PRIMARY KEY, 
    Point GEOGRAPHY 
) 

DECLARE @Point1 GEOGRAPHY; 
DECLARE @Point2 GEOGRAPHY; 
DECLARE @Point3 GEOGRAPHY; 
DECLARE @Point4 GEOGRAPHY; 
DECLARE @PointBufferDistanceInMeters INT; 

SET @Point1 = GEOGRAPHY::STPointFromText('POINT(1 52.50)', 4326); 
SET @Point2 = GEOGRAPHY::STPointFromText('POINT(1 52.51)', 4326); 
SET @Point3 = GEOGRAPHY::STPointFromText('POINT(1 52.52)', 4326); 
SET @Point4 = GEOGRAPHY::STPointFromText('POINT(1 52.52)', 4326); 
SET @PointBufferDistanceInMeters = 1000; 

--SELECT @Point1.STDistance(@Point2); 
--SELECT @Point1.STDistance(@Point3); 
--SELECT @Point1.STDistance(@Point4); 
--SELECT @Point2.STDistance(@Point3); 

INSERT INTO #Source 
    SELECT @Point1 
     UNION ALL 
    SELECT @Point2 
     UNION ALL 
    SELECT @Point3 
     UNION ALL 
    SELECT @Point4 

INSERT INTO #TargetSeeded 
    SELECT @Point1 
     UNION ALL 
    SELECT @Point2 

CREATE SPATIAL INDEX SpatialIndex ON #Source([Point]); 
CREATE SPATIAL INDEX SpatialIndex ON #TargetEmpty([Point]); 
CREATE SPATIAL INDEX SpatialIndex ON #TargetSeeded([Point]); 

-- Identify Ids to be inserted 
DELETE FROM #Source WHERE Id NOT IN 
(
    SELECT 
     Id 
    FROM #Source WHERE Id NOT IN 
    (
     SELECT 
      So.Id 
     FROM #Source AS So 
     INNER JOIN #TargetSeeded AS Ta 
     ON So.Point.STDistance(Ta.Point) < @PointBufferDistanceInMeters 
    ) 
) 

SELECT 
    * 
FROM #Source o 
WHERE o.Id IN 
(
    SELECT MAX(i.Id) 
    FROM #Source i 
    WHERE 
     i.Point.STDistance(o.Point) < @PointBufferDistanceInMeters 
) 
+0

也許一個視覺例子會更好。你是否有一個重要的名單,並希望選擇點,那些需要1000米的appart,就像試圖創建倉庫來優化分配過程一樣?或者你已經有了這些點,並想要刪除每個點緩衝區內的所有點?第一個需要非常大的優化過程,第二個非常容易使用'contains'功能 –

+0

您似乎在檢查'#Source'和'#TargetSeeded'行之間的距離。你保證沒有任何行_within_'#Source'違反你的1000米規則嗎? – HABO

+0

@Habo - 請參閱PS - 相關的子查詢嘗試 – cs0815

回答

1

這是否幫助?

-- Sample data. 
declare @Source as Table (Id Int Identity Primary Key, Point Geography); 
insert into @Source (Point) values 
    (Geography::STPointFromText('Point(1 52.50)', 4326)), 
    (Geography::STPointFromText('Point(1 52.51)', 4326)), 
    (Geography::STPointFromText('Point(1 52.52)', 4326)), 
    (Geography::STPointFromText('Point(1 52.52)', 4326)); 
select *, Point.ToString() as DecodedPoint from @Source; 

declare @Target as Table (Id Int Identity Primary Key, Point Geography); 
insert into @Target (Point) values 
    (Geography::STPointFromText('Point(1 52.50)', 4326)), 
    (Geography::STPointFromText('Point(1 52.51)', 4326)); 
select *, Point.ToString() as DecodedPoint from @Target; 

declare @PointBufferDistanceInMeters as Int = 1000; 

-- Merge the data.  
insert into @Target 
    select Point 
    from @Source as S 
    where 
     -- Remove rows that conflict with another Source row. 
     not exists (select 42 from @Source where S.Point.STDistance(Point) < @PointBufferDistanceInMeters and S.Id < Id) and 
     -- Remove rows that conflict with an existing Target row. 
     not exists (select 42 from @Target where S.Point.STDistance(Point) < @PointBufferDistanceInMeters) 
select *, Point.ToString() as DecodedPoint from @Target; 
+0

謝謝,看起來不錯,可能不那麼笨拙,那麼我的原始嘗試。你能告訴我'選擇42'的意思嗎? – cs0815

+2

@csetzkorn 42 is [the answer](https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker's_Guide_to_the_Galaxy#Answer_to_the_Ultimate_Question_of_Life.2C_the_Universe.2C_and_Everything_.2842.29)!它是一個方便的佔位符,其語法需要一個值或表達式,但它永遠不會被使用,例如,在'exists'查詢中。 – HABO

+0

哈哈 - 我怎麼會錯過這個( - : – cs0815