Skip to content

Instantly share code, notes, and snippets.

@JerryNixon
Last active October 14, 2025 15:43
Show Gist options
  • Select an option

  • Save JerryNixon/9de683bffb210ff7bd61ec4e1eeda41e to your computer and use it in GitHub Desktop.

Select an option

Save JerryNixon/9de683bffb210ff7bd61ec4e1eeda41e to your computer and use it in GitHub Desktop.
This is a variant of Dijkstra's algorithm for SQL Graph, written in T-SQL.
/*
This script implements a two-hop variant of Dijkstra’s algorithm using SQL Server graph features.
It creates a graph with 1500 nodes and edges, then finds the shortest two-edge paths
between 5 source and 5 destination nodes. Execution time is measured using a stopwatch.
*/
SET NOCOUNT ON
WHILE (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
BEGIN TRANSACTION
EXEC STOPWATCH_RESET;
DROP TABLE IF EXISTS test_location;
CREATE TABLE test_location (CODE VARCHAR(50)) AS NODE;
DROP TABLE IF EXISTS test_shipsto;
CREATE TABLE test_shipsto
(
COST MONEY
, INDEX IDX_test_shipsto_FROMTO
UNIQUE CLUSTERED ($from_id, $to_id)
WITH (DATA_COMPRESSION = PAGE)
) AS EDGE;
-- create the node
WITH generator (ID, CODE) AS
(
SELECT 1, NEWID()
UNION ALL
SELECT ID + 1, NEWID()
FROM generator
WHERE ID < 1500
)
INSERT INTO test_location
SELECT CODE
FROM generator
OPTION (MAXRECURSION 0);
-- create the edge
WITH pairs (FROM_NODE, TO_NODE) AS
(
SELECT
FROMLOC.$node_id
, TOLOC.$node_id
FROM test_location AS FROMLOC
CROSS JOIN test_location AS TOLOC
WHERE FROMLOC.CODE != TOLOC.CODE
)
INSERT INTO test_shipsto
($from_id, $to_id, COST)
SELECT
FROM_NODE
, TO_NODE
, ABS(CHECKSUM(NEWID())) % 14
FROM pairs;
-- take the first 5
DECLARE @sources TABLE (CODE VARCHAR(1000));
INSERT INTO @sources
SELECT CODE
FROM test_location
ORDER BY CODE OFFSET 0 ROWS FETCH FIRST 5 ROWS ONLY;
-- take the second 5
DECLARE @destinations TABLE (CODE VARCHAR(1000));
INSERT INTO @destinations
SELECT CODE
FROM test_location
ORDER BY CODE OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY;
EXEC STOPWATCH_READ @message = 'After DDL & insert';
WITH two_edges (STARTNODE, ENDNODE, PATH, COST, RANK) AS
(
SELECT L1.CODE, L3.CODE
, CONCAT(L1.CODE, '->', L2.CODE, '->', L3.CODE)
, S1.COST + S2.COST
, ROW_NUMBER() OVER (PARTITION BY L1.CODE, L3.CODE ORDER BY S1.COST + S2.COST)
FROM test_location AS L1
, test_shipsto AS S1
, test_location AS L2
, test_shipsto AS S2
, test_location AS L3
WHERE MATCH(L1-(S1)->L2-(S2)->L3)
AND L1.CODE != L2.CODE
AND L1.CODE != L3.CODE
AND L2.CODE != L3.CODE
AND L1.CODE IN (SELECT S.CODE FROM @sources AS S)
AND L3.CODE IN (SELECT D.CODE FROM @destinations AS D)
)
SELECT *
FROM two_edges
WHERE RANK = 1
-------------------------------------------------
EXEC STOPWATCH_READ @message = 'After Version 1';
GO
/*
CREATE OR ALTER PROC STOPWATCH_RESET
@print BIT = 1
, @message NVARCHAR(1000) = NULL
AS
DECLARE @starttime VARCHAR(50) = SYSDATETIME();
EXEC sp_set_session_context N'start_time', @starttime;
IF (@print = 1)
BEGIN
SET @message = CONCAT('Start: ', @starttime, ' ', @message);
RAISERROR (@message, 0, 1) WITH NOWAIT;
END
GO
CREATE OR ALTER PROC STOPWATCH_READ
@reset BIT = 1
, @message NVARCHAR(1000) = NULL
AS
DECLARE @starttime DATETIME2(7) = CONVERT(DATETIME2(7), SESSION_CONTEXT(N'start_time'))
DECLARE @emptydate DATETIME2 = CAST('1900-01-01 00:00:00.0000000' as datetime2);
SET @message = CONCAT('Delta: ', CONVERT(time, DATEADD(ms, DATEDIFF(ms, @starttime, SYSDATETIME()), @emptydate)), ' ', @message)
RAISERROR (@message, 0, 1) WITH NOWAIT;
IF (@reset = 1)
EXEC STOPWATCH_RESET 0;
GO
CREATE OR ALTER PROCEDURE GENERATEDATA
@count INT = 10
AS
WITH data (ID, CODE) AS
(
SELECT 1, NEWID()
UNION ALL
SELECT ID + 1, NEWID()
FROM DATA
WHERE ID < @count
)
SELECT CODE FROM data
OPTION (MAXRECURSION 0);
*/
/*
Finds the shortest two-hop paths between 5 source and 5 destination nodes in a graph.
Uses SQL Server graph features with MATCH clause.
*/
SET NOCOUNT ON;
BEGIN TRY
WHILE (@@TRANCOUNT > 0) ROLLBACK TRANSACTION;
BEGIN TRANSACTION;
EXEC STOPWATCH_RESET;
-- Create node table
DROP TABLE IF EXISTS Locations;
CREATE TABLE Locations (LocationID VARCHAR(50)) AS NODE;
-- Create edge table with clustered index
DROP TABLE IF EXISTS ShippingRoutes;
CREATE TABLE ShippingRoutes
(
COST MONEY,
INDEX IDX_ShippingRoutes_FromTo UNIQUE CLUSTERED ($from_id, $to_id)
WITH (DATA_COMPRESSION = PAGE)
) AS EDGE;
-- Insert 1500 nodes
WITH generator (ID, LocationID) AS
(
SELECT 1, NEWID()
UNION ALL
SELECT ID + 1, NEWID()
FROM generator
WHERE ID < 1500
)
INSERT INTO Locations (LocationID)
SELECT LocationID
FROM generator
OPTION (MAXRECURSION 0);
-- Insert edges (sparse: 10% of possible pairs)
WITH pairs (FromNode, ToNode) AS
(
SELECT
L1.$node_id,
L2.$node_id
FROM Locations AS L1
CROSS JOIN Locations AS L2
WHERE L1.LocationID != L2.LocationID
AND ABS(CHECKSUM(NEWID())) % 100 < 10 -- 10% of edges
)
INSERT INTO ShippingRoutes ($from_id, $to_id, COST)
SELECT
FromNode,
ToNode,
RAND() * 100 -- More realistic cost range
FROM pairs;
-- Select 5 source nodes
DECLARE @Sources TABLE (LocationID VARCHAR(50));
INSERT INTO @Sources
SELECT LocationID
FROM Locations
ORDER BY LocationID
OFFSET 0 ROWS FETCH FIRST 5 ROWS ONLY;
-- Select 5 destination nodes
DECLARE @Destinations TABLE (LocationID VARCHAR(50));
INSERT INTO @Destinations
SELECT LocationID
FROM Locations
ORDER BY LocationID
OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY;
EXEC STOPWATCH_READ @message = 'After DDL and data insertion';
-- Find shortest two-hop paths
WITH TwoHopPaths (StartNode, EndNode, Path, TotalCost, PathRank) AS
(
SELECT
L1.LocationID,
L3.LocationID,
CONCAT(L1.LocationID, '->', L2.LocationID, '->', L3.LocationID),
S1.COST + S2.COST,
ROW_NUMBER() OVER (
PARTITION BY L1.LocationID, L3.LocationID
ORDER BY S1.COST + S2.COST
)
FROM Locations AS L1
JOIN ShippingRoutes AS S1 ON MATCH(L1-(S1)->L2)
JOIN Locations AS L2 ON MATCH(L2-(S2)->L3)
JOIN ShippingRoutes AS S2 ON MATCH(L2-(S2)->L3)
JOIN Locations AS L3 ON MATCH(L1-(S1)->L2-(S2)->L3)
WHERE L1.LocationID != L2.LocationID
AND L1.LocationID != L3.LocationID
AND L2.LocationID != L3.LocationID
AND EXISTS (SELECT 1 FROM @Sources S WHERE S.LocationID = L1.LocationID)
AND EXISTS (SELECT 1 FROM @Destinations D WHERE D.LocationID = L3.LocationID)
)
SELECT StartNode, EndNode, Path, TotalCost
FROM TwoHopPaths
WHERE PathRank = 1;
EXEC STOPWATCH_READ @message = 'After shortest path query';
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW;
END CATCH;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment