sql server: 最短路径
---------------------------------------------------------------------
-- Road System 道路
--------------------------------------------------------------------- -- Listing 9-3: DDL & Sample Data for Cities, Roads
SET NOCOUNT ON;
USE tempdb;
GO
IF OBJECT_ID('dbo.Roads') IS NOT NULL
DROP TABLE dbo.Roads;
GO
IF OBJECT_ID('dbo.Cities') IS NOT NULL
DROP TABLE dbo.Cities;
GO CREATE TABLE dbo.Cities
(
cityid CHAR(3) NOT NULL PRIMARY KEY,
city VARCHAR(30) NOT NULL,
region VARCHAR(30) NULL,
country VARCHAR(30) NOT NULL
); INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('ATL', 'Atlanta', 'GA', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('ORD', 'Chicago', 'IL', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('DEN', 'Denver', 'CO', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('IAH', 'Houston', 'TX', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('MCI', 'Kansas City', 'KS', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('LAX', 'Los Angeles', 'CA', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('MIA', 'Miami', 'FL', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('MSP', 'Minneapolis', 'MN', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('JFK', 'New York', 'NY', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('SEA', 'Seattle', 'WA', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('SFO', 'San Francisco', 'CA', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('ANC', 'Anchorage', 'AK', 'USA');
INSERT INTO dbo.Cities(cityid, city, region, country)
VALUES('FAI', 'Fairbanks', 'AK', 'USA'); CREATE TABLE dbo.Roads
(
city1 CHAR(3) NOT NULL REFERENCES dbo.Cities,
city2 CHAR(3) NOT NULL REFERENCES dbo.Cities,
distance INT NOT NULL,
PRIMARY KEY(city1, city2),
CHECK(city1 < city2),
CHECK(distance > 0)
); INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ANC', 'FAI', 359);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'ORD', 715);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'IAH', 800);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'MCI', 805);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'MIA', 665);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('ATL', 'JFK', 865);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'IAH', 1120);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'MCI', 600);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'LAX', 1025);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'MSP', 915);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'SEA', 1335);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('DEN', 'SFO', 1270);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('IAH', 'MCI', 795);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('IAH', 'LAX', 1550);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('IAH', 'MIA', 1190);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('JFK', 'ORD', 795);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('LAX', 'SFO', 385);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MCI', 'ORD', 525);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MCI', 'MSP', 440);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MSP', 'ORD', 410);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('MSP', 'SEA', 2015);
INSERT INTO dbo.Roads(city1, city2, distance) VALUES('SEA', 'SFO', 815);
GO SELECT * FROM dbo.Roads
GO WITH Roads2 --每对城市生成行
AS
(
SELECT city1 AS from_city,city2 AS to_city FROM dbo.Roads
UNION ALL
SELECT city2,city2 FROM dbo.Roads
),
RoadPaths AS
(
--返回第一级别的所有可到达的城市对
SELECT from_city,to_city,
CAST('.'+from_city+'.'+to_city+'.' AS VARCHAR(max)) AS path
FROM Roads2
UNION ALL
SELECT F.from_city,T.to_city,--返回下一级别的可到达的城市对
CAST(F.path+T.to_city+'.' AS VARCHAR(MAX)) --路径需要验明循环
FROM RoadPaths AS F
JOIN Roads2 AS T
ON CASE WHEN F.path LIKE '%.'+T.to_city+'.%' --如果to_city出现在from_city的路径中,则检测到循环
THEN 1 ELSE 0 END =0
AND F.to_city =T.from_city
)
SELECT DISTINCT from_city,to_city FROM RoadPaths;--返回Roads 的传递包
GO ---------------------------------------------------------------------
-- Undirected Cyclic Graph
--------------------------------------------------------------------- -- Listing 9-38: Transitive Closure of Roads (Undirected Cyclic Graph) 传递闭包
WITH Roads2 -- Two rows for each pair (f-->t, t-->f)
AS
(
SELECT city1 AS from_city, city2 AS to_city FROM dbo.Roads
UNION ALL
SELECT city2, city1 FROM dbo.Roads
),
RoadPaths AS
(
-- Return all first-level reachability pairs
SELECT from_city, to_city,
-- path is needed to identify cycles
CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
FROM Roads2 UNION ALL -- Return next-level reachability pairs
SELECT F.from_city, T.to_city,
CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
FROM RoadPaths AS F
JOIN Roads2 AS T
-- if to_city appears in from_city's path, cycle detected
ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
THEN 1 ELSE 0 END = 0
AND F.to_city = T.from_city
)
-- Return Transitive Closure of Roads
SELECT DISTINCT from_city, to_city
FROM RoadPaths;
GO -- Listing 9-39: Creation Script for the fn_RoadsTC UDF
IF OBJECT_ID('dbo.fn_RoadsTC') IS NOT NULL
DROP FUNCTION dbo.fn_RoadsTC;
GO CREATE FUNCTION dbo.fn_RoadsTC() RETURNS @RoadsTC TABLE (
from_city VARCHAR(3) NOT NULL,
to_city VARCHAR(3) NOT NULL,
PRIMARY KEY (from_city, to_city)
)
AS
BEGIN
DECLARE @added as INT; INSERT INTO @RoadsTC(from_city, to_city)
SELECT city1, city2 FROM dbo.Roads; SET @added = @@rowcount; INSERT INTO @RoadsTC
SELECT city2, city1 FROM dbo.Roads SET @added = @added + @@rowcount; WHILE @added > 0 BEGIN INSERT INTO @RoadsTC
SELECT DISTINCT TC.from_city, R.city2
FROM @RoadsTC AS TC
JOIN dbo.Roads AS R
ON R.city1 = TC.to_city
WHERE NOT EXISTS
(SELECT * FROM @RoadsTC AS TC2
WHERE TC2.from_city = TC.from_city
AND TC2.to_city = R.city2)
AND TC.from_city <> R.city2; SET @added = @@rowcount; INSERT INTO @RoadsTC
SELECT DISTINCT TC.from_city, R.city1
FROM @RoadsTC AS TC
JOIN dbo.Roads AS R
ON R.city2 = TC.to_city
WHERE NOT EXISTS
(SELECT * FROM @RoadsTC AS TC2
WHERE TC2.from_city = TC.from_city
AND TC2.to_city = R.city1)
AND TC.from_city <> R.city1; SET @added = @added + @@rowcount;
END
RETURN;
END
GO -- Use the fn_RoadsTC UDF --传递闭包函数
SELECT * FROM dbo.fn_RoadsTC();
GO -- Listing 9-40: All paths and distances in Roads (15262 rows)返回所有路径和距离
WITH Roads2
AS
(
SELECT city1 AS from_city, city2 AS to_city, distance FROM dbo.Roads
UNION ALL
SELECT city2, city1, distance FROM dbo.Roads
),
RoadPaths AS
(
SELECT from_city, to_city, distance,
CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
FROM Roads2 UNION ALL SELECT F.from_city, T.to_city, F.distance + T.distance,
CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
FROM RoadPaths AS F
JOIN Roads2 AS T
ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
THEN 1 ELSE 0 END = 0
AND F.to_city = T.from_city
)
-- Return all paths and distances
SELECT * FROM RoadPaths;
GO -- Listing 9-41: Shortest paths in Roads 返回最短路径
WITH Roads2
AS
(
SELECT city1 AS from_city, city2 AS to_city, distance FROM dbo.Roads
UNION ALL
SELECT city2, city1, distance FROM dbo.Roads
),
RoadPaths AS
(
SELECT from_city, to_city, distance,
CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
FROM Roads2 UNION ALL SELECT F.from_city, T.to_city, F.distance + T.distance,
CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
FROM RoadPaths AS F
JOIN Roads2 AS T
ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
THEN 1 ELSE 0 END = 0
AND F.to_city = T.from_city
),
RoadsMinDist -- Min distance for each pair in TC 每对城市的最短距离
AS
(
SELECT from_city, to_city, MIN(distance) AS mindist
FROM RoadPaths
GROUP BY from_city, to_city
)
-- Return shortest paths and distances 返回最短路径和距离
SELECT RP.*
FROM RoadsMinDist AS RMD
JOIN RoadPaths AS RP
ON RMD.from_city = RP.from_city
AND RMD.to_city = RP.to_city
AND RMD.mindist = RP.distance;
GO -- Listing 9-42: Load Shortest Road Paths Into a Table 把最短路径保存到表
WITH Roads2
AS
(
SELECT city1 AS from_city, city2 AS to_city, distance FROM dbo.Roads
UNION ALL
SELECT city2, city1, distance FROM dbo.Roads
),
RoadPaths AS
(
SELECT from_city, to_city, distance,
CAST('.' + from_city + '.' + to_city + '.' AS VARCHAR(MAX)) AS path
FROM Roads2 UNION ALL SELECT F.from_city, T.to_city, F.distance + T.distance,
CAST(F.path + T.to_city + '.' AS VARCHAR(MAX))
FROM RoadPaths AS F
JOIN Roads2 AS T
ON CASE WHEN F.path LIKE '%.' + T.to_city + '.%'
THEN 1 ELSE 0 END = 0
AND F.to_city = T.from_city
),
RoadsMinDist
AS
(
SELECT from_city, to_city, MIN(distance) AS mindist
FROM RoadPaths
GROUP BY from_city, to_city
)
SELECT RP.*
INTO dbo.RoadPaths
FROM RoadsMinDist AS RMD
JOIN RoadPaths AS RP
ON RMD.from_city = RP.from_city
AND RMD.to_city = RP.to_city
AND RMD.mindist = RP.distance; CREATE UNIQUE CLUSTERED INDEX idx_uc_from_city_to_city
ON dbo.RoadPaths(from_city, to_city);
GO -- Return shortest path between Los Angeles and New York 测试查询最短路径
SELECT * FROM dbo.RoadPaths
WHERE from_city = 'LAX' AND to_city = 'JFK';
GO -- Listing 9-43: Creation Script for the fn_RoadsTC UDF
IF OBJECT_ID('dbo.fn_RoadsTC') IS NOT NULL
DROP FUNCTION dbo.fn_RoadsTC;
GO
CREATE FUNCTION dbo.fn_RoadsTC() RETURNS @RoadsTC TABLE
(
uniquifier INT NOT NULL IDENTITY,
from_city VARCHAR(3) NOT NULL,
to_city VARCHAR(3) NOT NULL,
distance INT NOT NULL,
route VARCHAR(MAX) NOT NULL,
PRIMARY KEY (from_city, to_city, uniquifier)
)
AS
BEGIN
DECLARE @added AS INT; INSERT INTO @RoadsTC
SELECT city1 AS from_city, city2 AS to_city, distance,
'.' + city1 + '.' + city2 + '.'
FROM dbo.Roads; SET @added = @@rowcount; INSERT INTO @RoadsTC
SELECT city2, city1, distance, '.' + city2 + '.' + city1 + '.'
FROM dbo.Roads; SET @added = @added + @@rowcount; WHILE @added > 0 BEGIN
INSERT INTO @RoadsTC
SELECT DISTINCT TC.from_city, R.city2,
TC.distance + R.distance, TC.route + city2 + '.'
FROM @RoadsTC AS TC
JOIN dbo.Roads AS R
ON R.city1 = TC.to_city
WHERE NOT EXISTS
(SELECT * FROM @RoadsTC AS TC2
WHERE TC2.from_city = TC.from_city
AND TC2.to_city = R.city2
AND TC2.distance <= TC.distance + R.distance)
AND TC.from_city <> R.city2; SET @added = @@rowcount; INSERT INTO @RoadsTC
SELECT DISTINCT TC.from_city, R.city1,
TC.distance + R.distance, TC.route + city1 + '.'
FROM @RoadsTC AS TC
JOIN dbo.Roads AS R
ON R.city2 = TC.to_city
WHERE NOT EXISTS
(SELECT * FROM @RoadsTC AS TC2
WHERE TC2.from_city = TC.from_city
AND TC2.to_city = R.city1
AND TC2.distance <= TC.distance + R.distance)
AND TC.from_city <> R.city1; SET @added = @added + @@rowcount;
END
RETURN;
END
GO -- Return shortest paths and distances
SELECT from_city, to_city, distance, route
FROM (SELECT from_city, to_city, distance, route,
RANK() OVER (PARTITION BY from_city, to_city
ORDER BY distance) AS rk
FROM dbo.fn_RoadsTC()) AS RTC
WHERE rk = 1;
GO -- Cleanup
DROP TABLE dbo.RoadPaths;
GO
sql server: 最短路径的更多相关文章
- 在SQL Server实现最短路径的搜索
开始 这是去年的问题了,今天在整理邮件的时候才发现这个问题,感觉顶有意思的,特记录下来. 在表RelationGraph中,有三个字段(ID,Node,RelatedNode),其中Node和Rela ...
- 【转】T-SQL查询进阶—理解SQL Server中的锁
简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查 ...
- SQL Server中的锁的简单学习
简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的 ...
- T-SQL查询进阶—理解SQL Server中的锁
在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的.这些 ...
- 理解SQL Server中索引的概念
T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他 简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能 ...
- T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他
简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能,在OLAP中尤其明显.要完全理解索 ...
- 理解SQL Server中索引的概念,原理
转自:http://www.cnblogs.com/CareySon/archive/2011/12/22/2297568.html 简介 在SQL Server中,索引是一种增强式的存在,这意味着, ...
- T-SQL查询进阶--理解SQL Server中索引的概念,原理
简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,sql server仍然可以实现应有的功能,但索引可以在大多数情况下提升查询性能,在OLAP(On line Trans ...
- 理解SQL Server中索引的概念,原理以及其他(转载)
简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能,在OLAP中尤其明显.要完全理解索 ...
随机推荐
- 一些有价值的Blog推荐
待看的一些文章 1. 性能调优攻略 http://coolshell.cn/articles/7490.html 2. 内存的存储管理--段式和页式管理的区别 http://blog.sina.com ...
- ASP.NET Core OceLot 微服务实践
1.OceLot中间件介绍 在传统的BS应用中,随着业务需求的快速发展变化,需求不断增长,迫切需要一种更加快速高效的软件交付方式.微服务可以弥补单体应用不足,是一种更加快速高效软件架构风格.单体应用被 ...
- Spring集合注入
1.集合注入 上一篇博客讲了spring得属性注入,通过value属性来配置基本数据类型,通过<property>标签的 ref 属性来配置对象的引用.如果想注入多个数据,那我们就要用到集 ...
- Navicat Premium Mac V12.0.22.0 中英文破解 亲测可用
换了Mac电脑后网上找了好些个 Navicat Premium 破解版本, 特别是CSDN上要积分下载的也不能用,浪费积分下,都是些坑爹破解方法,浪费了好些时间,今天介绍看到的一套有效的破解过程 1. ...
- PHP校验日期格式是否合法
在后端开发中,我们常常需要校验前端传入参数的合法性,如果是校验日期参数,我们可以通过下面的方法来校验: /** * 校验日期格式是否合法 * @param string $date * @param ...
- 第二十八节:Java基础-进阶继承,抽象类,接口
前言 Java基础-进阶继承,抽象类,接口 进阶继承 class Stu { int age = 1; } class Stuo extends Stu { int agee = 2; } class ...
- Java学习笔记45(多线程二:安全问题以及解决原理)
线程安全问题以及解决原理: 多个线程用一个共享数据时候出现安全问题 一个经典案例: 电影院卖票,共有100座位,最多卖100张票,买票方式有多种,网上购买.自主售票机.排队购买 三种方式操作同一个共享 ...
- kubernetes集群搭建(1):环境准备
了解kubernets 本次搭建采用的是1个master节点,2个node节点,一个私有docker仓库 1.设置各节点ip信息 2.设置hostname(其它节点也需修改) vi /etc/sysc ...
- Maven - 实例-2-使用本地仓库中的依赖包
Maven引入构建包的流程 执行mvn compile命令编译源代码,如果编译过程中需要用到其他的包, maven将会在pom.xml文件中查找是否引入该依赖包的坐标. 示例: <depende ...
- Spring Boot自动配置原理、实战
Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...