MSSQL 2008R2避免矩阵表中的重复项

时间:2014-06-05 22:45:54

标签: sql sql-server arrays matrix

我试图为此找到解决方案,当记录低于某个数字时,它在某种程度上很容易解决。但...

我有一份包含81,590条记录的原始列表。

Id  Loc Sales   LatLong
1   a   100 ...
2   b   110 ...
3   c   105 ...
4   d   125 ...
5   e   123 ...
6   f   35  ...
.
.
.
81,590  ... ... ...

我需要将列表中的所有项目相互比较。

    Id  L1  L2  Dist    
    1   a   a   0   --> Not needed. Self comparison.
    2   a   b   26  
    3   a   c   150 --> Not needed. Distance >100.
    4   a   d   58  
    5   b   a   26  --> Not needed. Repeated record.
    6   b   b   0   --> Not needed. Self comparison.
    7   b   c   15  
    8   b   d   151 --> Not needed. Distance >100.
    9   c   a   150 --> Not needed. Repeated record.
    10  c   b   15  --> Not needed. Repeated record.
    11  c   c   0   --> Not needed. Self comparison.
    12  c   d   75  
    13  d   a   58  --> Not needed. Repeated record.
    14  d   b   151 --> Not needed. Repeated record.
    15  d   c   75  --> Not needed. Repeated record.
    16  d   d   0   --> Not needed. Self comparison.

但如上面记录旁边所示,最终结果必须是以下列表:

1)仅当记录位于特定距离时(例如<100英里),才能将记录相互比较。

2)在将Loc1与Loc2进行比较与将Loc2与Loc1进行比较相同的意义上,不包含重复项。

3)显而易见的是,无需将Loc1与自身进行比较。

最终结果将是:

    Id  L1  L2  Dist
    2   a   b   26
    4   a   d   58
    7   b   c   15
    12  c   d   75

方法:

理论上,将所有项目与自己进行比较后的记录总数为81,590 ^ 2 = 6,656,928,100条记录。

减去重复的迭代次数(LocA-LocB = LocB-LocA)意味着6,656,928,100 / 2 = 3,328,464,050。

通过摆脱自重复迭代(LocA-LocA)进一步清理,应为3,328,464,050 - 81,590 = 3,328,382,460。

然后我可以摆脱所有带距离的记录&gt; 100英里。

这是非常低效的,我正在构建一个包含6Bn记录的表,然后删除一半等等。


是否有方法以更高效(更少步骤,更少选择/删除/更新)的方式到达最终产品?

将最终数据集插入目标所需的select语句是什么?

听起来像是表格与自身的连接以及按键的迭代过滤,但这里是我被卡住的地方。

2 个答案:

答案 0 :(得分:0)

您使用什么算法来计算两点之间的距离?简单的“世界是扁平的”笛卡尔数学,或那个三角函数“这个词是扁圆形的”是一个吗?这可能会变成严重的CPU要求。

最好生成一个“位于该位置距离X内的位置”的表格,并将其永久存储;除非像地震这样的重大事件,否则它不会改变。

查询方面,基本连接很简单:

SELECT
   t1.Loc L1
  ,t2.Loc L2
 from MyTable t1
  inner join MyTable t2
   on t2.Loc > t1.Loc

如果在名为“distanceFunction”的函数中有距离公式,它可能看起来像:

WITH cteCalc as (
    select
       t1.Loc L1
      ,t2.Loc L2
      ,dbo.distanceFunction(t1.LatLong, t2.LatLong) Dist
     from MyTable t1
      inner join MyTable t2
       on t2.Loc > t1.Loc
     where dbo.distanceFunction(t1.LatLong, t2.LatLong) < @MaxDistance)
 INSERT TargetTable (L1, L2, Dist)
 SELECT
    L1
   ,L2
   ,Dist
  where Dist <= @MaxDistance

当然,这可能会破坏您的系统,只是因为当您向目标表写入数十亿行时,事务日志会变得太大。我说要构建一个循环,依次处理每个位置,最后的查询如下:

WITH cteCalc as (
    select
       t1.Loc L1
      ,t2.Loc L2
      ,dbo.distanceFunction(t1.LatLong, t2.LatLong) Dist
     from MyTable t1
      inner join MyTable t2
       on t2.Loc > t1.Loc
     where dbo.distanceFunction(t1.LatLong, t2.LatLong) < @MaxDistance
      and t1.Loc = @ThisIterationLoc)
 INSERT TargetTable (L1, L2, Dist)
 SELECT
    L1
   ,L2
   ,Dist
  where Dist <= @MaxDistance

第一次传球返回81,589,无论哪个太远,第二次传球为81,588,等等。

答案 1 :(得分:0)

以下是我将如何解决此问题的概述:

  1. 在纬度和经度上放置索引
  2. 对距离范围(方框)的lat和长距离进行数学计算。然后你知道你的距离(如方框不是圆圈)包含在这个三角形中。你也知道它不在这个三角洲之外。这大大限制了这个问题。

    例如,如果lat和long的变化对于你的距离是10,那么你的盒子的位置(100,100)将由lat和long的(95,95)和(105,105)值定义。 / EM>

  3. 编写一个查询每个元素(来自最低ID)的查询,并在lat和log的delta中搜索其他元素(具有更大的id以避免重复),并将其保存到临时表中。
  4. 对该表进行迭代并进行完整计算以查看它是否在您距离的圆圈内(而不是方框内)。