2016-01-23 32 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