子选择 MySQL
Subselect in MySQL
我有以下 table,代表公共汽车和停靠点。
bus_table
bus stop_no station_id
1 1 1
1 2 2
1 3 3
2 1 7
2 2 8
2 3 9
3 1 3
3 2 4
3 3 5
3 4 6
3 5 7
我想从 1 号站到 9 号站。
我可以为此编写什么查询?
举个例子。显然,此解决方案不是递归的 - 但您可以继续遍历公交路线,直到从 A 到达 B。
DROP TABLE IF EXISTS bus_routes;
CREATE TABLE bus_routes
(bus_no INT NOT NULL
,stop_no INT NOT NULL
,station_id INT NOT NULL
,PRIMARY KEY(bus_no,stop_no)
);
INSERT INTO bus_routes VALUES
(1,1,1),
(1,2,2),
(1,3,3),
(2,1,7),
(2,2,8),
(2,3,9),
(3,1,3),
(3,2,4),
(3,3,5),
(3,4,6),
(3,5,7);
SELECT a_from.bus_no
, a_from.station_id start_from
, b_from.station_id first_change_at
, b_from.bus_no to_bus
, c_from.station_id then_change_at
, c_from.bus_no to_bus
, c_to.station_id alighting_at
FROM bus_routes a_from
JOIN bus_routes a_to
ON a_to.bus_no = a_from.bus_no
AND a_to.stop_no > a_from.stop_no
JOIN bus_routes b_from
ON b_from.station_id = a_to.station_id
JOIN bus_routes b_to
ON b_to.bus_no = b_from.bus_no
AND b_to.stop_no > b_from.stop_no
JOIN bus_routes c_from
ON c_from.station_id = b_to.station_id
JOIN bus_routes c_to
ON c_to.bus_no = c_from.bus_no
AND c_to.stop_no > c_from.stop_no
WHERE a_from.station_id = 1
AND c_to.station_id = 9;
+--------+------------+-----------------+--------+----------------+--------+--------------+
| bus_no | start_from | first_change_at | to_bus | then_change_at | to_bus | alighting_at |
+--------+------------+-----------------+--------+----------------+--------+--------------+
| 1 | 1 | 3 | 3 | 7 | 2 | 9 |
+--------+------------+-----------------+--------+----------------+--------+--------------+
公交车站图的递归遍历(在 MSSQL 2016 上测试):
DECLARE @from NCHAR(4) = 'ort1';
DECLARE @to NCHAR(4) = 'ort9';
WITH [route] ([path], [lastBus], [current])
AS
(SELECT CAST(N'' AS NVARCHAR(1000)) AS [path], CAST(N'' AS NCHAR(2)) AS [lastBus], @from AS [current]
UNION ALL
SELECT CAST( cur.[path] + N',' + busesAvailable.name + N' to ' + [next].stat AS NVARCHAR(1000)) AS [path],
busesAvailable.name AS [lastBus],
[next].stat AS [current]
FROM [route] cur
INNER JOIN dbo.BusStat busesAvailable ON busesAvailable.stat = cur.[current] AND busesAvailable.name <> cur.[lastBus]
INNER JOIN dbo.BusStat [next]
ON [next].stat <> cur.[current]
AND [next].name = busesAvailable.name)
SELECT TOP 1 [route].[path]
FROM [route]
WHERE [route].[current] = @to;
考虑到 table 是通过以下方式创建的:
CREATE TABLE [dbo].[BusStat]
(
[name] NCHAR (2) NOT NULL,
[stat] NCHAR (4) NOT NULL
);
INSERT INTO [dbo].[BusStat] ([name], [stat])
SELECT 'b1', 'ort1' UNION ALL
SELECT 'b1', 'ort2' UNION ALL
SELECT 'b1', 'ort3' UNION ALL
SELECT 'b2', 'ort7' UNION ALL
SELECT 'b2', 'ort8' UNION ALL
SELECT 'b2', 'ort9' UNION ALL
SELECT 'b3', 'ort3' UNION ALL
SELECT 'b3', 'ort4' UNION ALL
SELECT 'b3', 'ort5' UNION ALL
SELECT 'b3', 'ort6' UNION ALL
SELECT 'b3', 'ort7';
我有以下 table,代表公共汽车和停靠点。
bus_table
bus stop_no station_id
1 1 1
1 2 2
1 3 3
2 1 7
2 2 8
2 3 9
3 1 3
3 2 4
3 3 5
3 4 6
3 5 7
我想从 1 号站到 9 号站。
我可以为此编写什么查询?
举个例子。显然,此解决方案不是递归的 - 但您可以继续遍历公交路线,直到从 A 到达 B。
DROP TABLE IF EXISTS bus_routes;
CREATE TABLE bus_routes
(bus_no INT NOT NULL
,stop_no INT NOT NULL
,station_id INT NOT NULL
,PRIMARY KEY(bus_no,stop_no)
);
INSERT INTO bus_routes VALUES
(1,1,1),
(1,2,2),
(1,3,3),
(2,1,7),
(2,2,8),
(2,3,9),
(3,1,3),
(3,2,4),
(3,3,5),
(3,4,6),
(3,5,7);
SELECT a_from.bus_no
, a_from.station_id start_from
, b_from.station_id first_change_at
, b_from.bus_no to_bus
, c_from.station_id then_change_at
, c_from.bus_no to_bus
, c_to.station_id alighting_at
FROM bus_routes a_from
JOIN bus_routes a_to
ON a_to.bus_no = a_from.bus_no
AND a_to.stop_no > a_from.stop_no
JOIN bus_routes b_from
ON b_from.station_id = a_to.station_id
JOIN bus_routes b_to
ON b_to.bus_no = b_from.bus_no
AND b_to.stop_no > b_from.stop_no
JOIN bus_routes c_from
ON c_from.station_id = b_to.station_id
JOIN bus_routes c_to
ON c_to.bus_no = c_from.bus_no
AND c_to.stop_no > c_from.stop_no
WHERE a_from.station_id = 1
AND c_to.station_id = 9;
+--------+------------+-----------------+--------+----------------+--------+--------------+
| bus_no | start_from | first_change_at | to_bus | then_change_at | to_bus | alighting_at |
+--------+------------+-----------------+--------+----------------+--------+--------------+
| 1 | 1 | 3 | 3 | 7 | 2 | 9 |
+--------+------------+-----------------+--------+----------------+--------+--------------+
公交车站图的递归遍历(在 MSSQL 2016 上测试):
DECLARE @from NCHAR(4) = 'ort1';
DECLARE @to NCHAR(4) = 'ort9';
WITH [route] ([path], [lastBus], [current])
AS
(SELECT CAST(N'' AS NVARCHAR(1000)) AS [path], CAST(N'' AS NCHAR(2)) AS [lastBus], @from AS [current]
UNION ALL
SELECT CAST( cur.[path] + N',' + busesAvailable.name + N' to ' + [next].stat AS NVARCHAR(1000)) AS [path],
busesAvailable.name AS [lastBus],
[next].stat AS [current]
FROM [route] cur
INNER JOIN dbo.BusStat busesAvailable ON busesAvailable.stat = cur.[current] AND busesAvailable.name <> cur.[lastBus]
INNER JOIN dbo.BusStat [next]
ON [next].stat <> cur.[current]
AND [next].name = busesAvailable.name)
SELECT TOP 1 [route].[path]
FROM [route]
WHERE [route].[current] = @to;
考虑到 table 是通过以下方式创建的:
CREATE TABLE [dbo].[BusStat]
(
[name] NCHAR (2) NOT NULL,
[stat] NCHAR (4) NOT NULL
);
INSERT INTO [dbo].[BusStat] ([name], [stat])
SELECT 'b1', 'ort1' UNION ALL
SELECT 'b1', 'ort2' UNION ALL
SELECT 'b1', 'ort3' UNION ALL
SELECT 'b2', 'ort7' UNION ALL
SELECT 'b2', 'ort8' UNION ALL
SELECT 'b2', 'ort9' UNION ALL
SELECT 'b3', 'ort3' UNION ALL
SELECT 'b3', 'ort4' UNION ALL
SELECT 'b3', 'ort5' UNION ALL
SELECT 'b3', 'ort6' UNION ALL
SELECT 'b3', 'ort7';