2
  • I have the following table containing n bins in a warehouse and their coordinate points on a map.
  • I would like to find the distance between every point in the list.
  • I have attempted to use a pivot, cross apply, cross join, etc and ultimately get nowhere close to the intended result (typically get an error) so I will refrain from posting my code here..
  • Below is my sample data and my desired output.
  • ...and once found, how can I insert the shortest path/route into a new temporary-table?

Sample Data:

BinCoord BinNumb
(27,1) S
(18,2) D1
(24,2) B1
(15,23) E20

Desired output:

(Distances are placeholders, not actual values). I'm not too bothered about how the BinPath is represented: e.g. a To and From column would also work fine.

Distance BinPath
3.32 S-D1
5.54 D1-B1
7.62 B1-E20
2.23 D1-E20

I would assume this needs to be in some sort of loop or maybe is achievable in a pivot with some dynamic SQL. My apologies for not having a better attempted path.


Here is what I tried:

It takes my sample data and apparently does nothing because I don't understand what I need to do. My aim was to create a matrix and then do some sort of loop or cross apply to find distances between all points in the matrix.

SELECT
    D1.[BinCoord],
    D1.[BinNum]
FROM
    ##Djik3 D1
    CROSS JOIN ##Djik3 D2
WHERE
    D1.BinCoord = D2.BinCoord
    AND
    D1.BinNum = D2.BinNum
Dai
  • 141,631
  • 28
  • 261
  • 374
ayecob
  • 37
  • 5
  • Exactly what RDBMS are you using? Does it have built-in support for spatial-types? (aka geometry/geospatial types?) (most modern RDBMS do) - if it does then you should use that built-in functionality for computing distances etc. – Dai Nov 01 '22 at 01:15
  • _"so I will refrain from posting my code here"_ - no, you **should** still post it so that we can let you know where you're going wrong. – Dai Nov 01 '22 at 01:15
  • I am using SSMS on SQL Server 12.0 I will update the question and post my code, it apparently does nothing to my sample data. – ayecob Nov 01 '22 at 01:17
  • It is not normally necessary to find _every_ distance between _every_ nose, in SQL you can efficiently find the nearest point or implement many path optimisations using spatial queries in SQL directly – Chris Schaller Nov 01 '22 at 01:19
  • @ChrisSchaller My ultimate goal is to find the shortest path between all points. I am taking a step by step approach probably far from the optimal method because I am a beginner. If you had advice on how to achieve this aim using a better method please feel free to share – ayecob Nov 01 '22 at 01:21
  • @JacobRoutier _"My ultimate goal is to find the shortest path between all points"_ - uhhh, are you familiar with the Travelling Salesman Problem? ...or at least Dijkstra's Algorithm? – Dai Nov 01 '22 at 01:29
  • research `shortest distance manhattan` – jsotola Nov 01 '22 at 01:31
  • Microsoft doesn't refer to SQL Server versions by number, only their marketing name - version 12.0 is SQL Server 2014 which is _almost_ obsolete now - is there any way you can update to a more modern version? – Dai Nov 01 '22 at 01:32
  • 1
    @jsotola _"shortest distance manhattan"_ - ah yes, that's the name of my favourite cocktail (i.e. the most nearest one) – Dai Nov 01 '22 at 01:33
  • @Dai Yes, I am actually trying to implement Dijkstra's Algorithm but having a hard time finding solutions out there already so trying to work through my own. And no, unfortunately I am not able to upgrade. It is an Azure server and I am not the admin – ayecob Nov 01 '22 at 01:33
  • @JacobRoutier By "Azure" do you mean Azure SQL - or Azure Managed Instance? If the former, then the "12.0" displayed in Object Explorer is a lie: it's _always_ reported as 12.0 for some reason, the effective "real" version is somewhere in-between SQL Server 2019 and SQL Server 2022. – Dai Nov 01 '22 at 01:35
  • @Dai Azure SQL so yes I guess it will show 12.0 regardless – ayecob Nov 01 '22 at 01:36
  • [Here's a loop-based implementation of Dijkstra's in T-SQL implemented in 2006](http://hansolav.net/blog/ImplementingDijkstrasAlgorithmUsingTSQL.aspx) but I _do not_ recommend this approach today given that we now have support for self-referential CTEs and Graph Tables (with node pattern matching, kinda like a good-enough implementation of neo4j's graph query language). If you're able to create new DB objects, have you considered creating a [Graph Table](https://learn.microsoft.com/en-us/sql/relational-databases/graphs/sql-graph-architecture) representation of your data as a starting point? – Dai Nov 01 '22 at 01:37
  • @Dai Thank you so much, I will look into the link. And yes, I do have permissions to create new objects but this is the first I am hearing of a graph table. Looks like what I would need so I will give it a try. Thank you so much – ayecob Nov 01 '22 at 01:39

1 Answers1

2

The process is the same in later versions, expect that we can use built in functionality.

  • For just simple 2D distance this is probably going to have a similar level of performance

We can build your table using a CTE to first parse the BinCoords into numeric values, if you have a massive amount of records then you might compute this into its own temp table first (or build the CTE logic into the query that build the #Djik3 temp table):

-- Format the data first!
WITH BinCoords as (
    SELECT 
          BinCoord
        , BinNumb
        , X = CAST(SUBSTRING(BinCoord, 2, Fx1.Comma - 2) as real)
        , Y = CAST(SUBSTRING(BinCoord, Fx1.Comma + 1, LEN(BinCoord) - Fx1.Comma - 1) as real)
    FROM #Djik3 d
    CROSS APPLY (SELECT CHARINDEX(',', BinCoord) as Comma) as Fx1
)
SELECT 
      [From] = src.BinNumb
    , [To] = tgt.BinNumb
    , [BinPath] = CONCAT(src.BinNumb,'-',tgt.BinNumb)
    , [Distance] = SQRT(((src.X - tgt.X)*(src.X - tgt.X))+((src.Y - tgt.Y)*(src.Y - tgt.Y)))
FROM BinCoords src
CROSS JOIN BinCoords tgt
WHERE src.BinNumb > tgt.BinNumb
From To BinPath Distance
S D1 S-D1 9.055385138137417
E20 D1 E20-D1 21.213203435596427
S B1 S-B1 3.1622776601683795
D1 B1 D1-B1 6
E20 B1 E20-B1 22.847319317591726
S E20 S-E20 25.059928172283335

Using simple Pythagoras formula to calculate the distance

The tricky thing with a CROSS JOIN is that you will get all the results of A-B and B-A, including B-B and A-A. The simple way to only get the unique path combinations is to use a less than, or greater than comparison on the node identifier.

  • I have used A > B to get the larger node first to match your expectation, but A < B would have worked equally well.

See this Fiddle: http://sqlfiddle.com/#!18/74cbba/3


UPDATE: Dijkstras Algorithm needs the reverse paths too!

If the purpose of computing the node distances is to use Dijkstras Algorithm to find the shortest route between the nodes, then we need the reverse paths to, so the only path to exclude in the SQL is A-A, for that we change the filter:

FROM BinCoords src
CROSS JOIN BinCoords tgt
WHERE src.BinNumb <> tgt.BinNumb

Fiddle: http://sqlfiddle.com/#!18/74cbba/1

From To Path Distance
D1 S D1-S 9.05538513813742
B1 S B1-S 3.16227766016838
E20 S E20-S 25.0599281722833
S D1 S-D1 9.05538513813742
B1 D1 B1-D1 6
E20 D1 E20-D1 21.2132034355964
S B1 S-B1 3.16227766016838
D1 B1 D1-B1 6
E20 B1 E20-B1 22.8473193175917
S E20 S-E20 25.0599281722833
D1 E20 D1-E20 21.2132034355964
B1 E20 B1-E20 22.8473193175917

Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
  • thank you so much for your answer, I really appreciate it. I am implementing it now and will comment back if I run into any issues. – ayecob Nov 01 '22 at 22:33
  • It doesn't actually run dijkstras but this table helps you get there. Storing your data in a more code friendly manner with Ids and discrete values for X and Y ordinates, or using geometry data types will make this sort of logic easier in the future. – Chris Schaller Nov 01 '22 at 22:39
  • Worked brilliantly! Thank you. Also yes you are correct but this format is exactly what I need as inputs for the rest of my code. – ayecob Nov 01 '22 at 22:46