Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle(1)
.pdfПример 47: формирование и анализ связанных структур
MySQL |
Решение 7.1.2.b (код процедуры, второй вариант) (продолжение) |
120-- Добавляем связь в текущий путь
121INSERT INTO `current_path`
122 |
|
(`cp_id`, |
123 |
|
`cp_from`, |
124 |
|
`cp_to`, |
125 |
|
`cp_cost`, |
126 |
|
`cp_bidir`) |
127 |
|
VALUES (NULL, |
128 |
|
cn_from_value, |
129 |
|
cn_to_value, |
130 |
|
cn_cost_value, |
131 |
|
cn_bidir_value); |
132 |
|
|
133-- Продолжаем рекурсивно искать следующие связи
134CALL FIND_PATH (start_node, finish_node);
135
136-- Удаляем последнюю связь из текущего пути
137SET @max_cp_id = (SELECT MAX(`cp_id`)
138 |
|
FROM `current_path`); |
139DELETE FROM `current_path`
140WHERE `cp_id` = @max_cp_id;
141END IF;
142END LOOP nodes_loop;
143CLOSE nodes_cursor;
144END;
145$$
146DELIMITER ;
Проверим, как работают полученные решения, выполнив такой код.
MySQL |
Решение 7.1.2.b (код для проверки работоспособности) |
1-- Для первого варианта решения:
2CALL FIND_PATH({начальная_точка}, {конечная_точка});
3
4-- Для второго варианта решения:
5TRUNCATE TABLE `current_path`;
6TRUNCATE TABLE `final_paths`;
7CALL FIND_PATH({начальная_точка}, {конечная_точка});
8SELECT * FROM `final_paths`;
На представленном в начале данного примера наборе данных для поиска пути из города 1 в город 6 оба решения возвращают одинаковые (хоть и по-разному представленные) результаты.
Результат первого варианта решения:
cn_from |
cn_to |
cn_cost |
cn_bidir |
cn_steps |
cn_route |
1 |
6 |
30 |
N |
3 |
1,7,3,6 |
1 |
6 |
85 |
N |
3 |
1,7,2,6 |
Результат второго варианта решения:
fp_id |
fp_from |
fp_to |
fp_cost |
fp_bidir |
0.42358866466543516 |
1 |
7 |
20 |
N |
0.42358866466543516 |
7 |
2 |
15 |
Y |
0.42358866466543516 |
2 |
6 |
50 |
N |
0.34713028031134074 |
1 |
7 |
20 |
N |
0.34713028031134074 |
7 |
3 |
5 |
N |
0.34713028031134074 |
3 |
6 |
5 |
N |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 500/545
Пример 47: формирование и анализ связанных структур
Но если в таблицу connections поместить следующие данные
cn_from |
cn_to |
cn_cost |
cn_bidir |
1 |
3 |
100 |
N |
1 |
5 |
100 |
N |
3 |
5 |
20 |
N |
5 |
3 |
200 |
N |
и поискать путь между городами 1 и 5, результаты будут разными. Результат первого варианта решения:
cn_from |
cn_to |
cn_cost |
cn_bidir |
|
cn_steps |
cn_route |
||||||
1 |
|
5 |
100 |
|
N |
|
1 |
1,5 |
|
|
||
|
Результат второго варианта решения: |
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|||
|
fp_id |
|
fp_from |
fp_to |
|
fp_cost |
fp_bidir |
|
||||
0.6203666074391143 |
1 |
|
3 |
|
|
100 |
N |
|
|
|||
0.6203666074391143 |
3 |
|
5 |
|
|
20 |
N |
|
|
|||
0.2569376912498266 |
1 |
|
5 |
|
|
100 |
N |
|
|
Как и было сказано выше, первый вариант решения не находит альтернативные пути разной длины, в то время как второй вариант справляется с этим.
На этом решение для MySQL завершено.
Переходим к MS SQL Server и реализуем один-в-один решение, представленное выше для MySQL.
Алгоритм первого варианта решения:
•удаляется (если существует) и создаётся временная таблица для хранения найденных путей (строки 7-19);
•в созданную таблицу переносятся все данные из таблицы connections с учётом двунаправленности некоторых связей (строки 23-42; аналогичный подзапрос, учитывающий двунаправленные связи, используется в строках 69-81 — фактически, он представляет собой ничто иное, как тело представления из решения{492} задачи 7.1.2.a{491});
•выполняется цикл поиска производных маршрутов (строки 46-93), в котором: o условием выхода является отсутствие новых маршрутов (переменная MS SQL Server @@ROWCOUNT содержит количество записей, затронутых
последней операцией модификации данных);
oидея поиска новых маршрутов строится на том, чтобы к уже найденным маршрутам добавлять следующие шаги (конечная точка найденного маршрута совпадает с отправной точкой связи между городами, что проверяется в условии объединения в строке 82; условие в строках 83-84 исключает порождение циклических маршрутов; условие в строках 89-90 исключает бесконечное повторное дублирующихся маршрутов между двумя любыми городами).
•после того, как все возможные производные маршруты построены, в качестве результата работы хранимой процедуры возвращаются только те маршруты, точки отправки и назначения которых совпадают с переданными в хранимую процедуру параметрами (строки 96-100).
Обратите внимание на то, как формируется и анализируется маршрут, раз-
мещаемый в поле cn_route таблицы connections_temp: в MS SQL Server нет прямого аналога функции MySQL FIND_IN_SET, а при поиске вхождения подстроки
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 501/545
Пример 47: формирование и анализ связанных структур
в строку есть шанс, например, «найти» число 12 в числе 123 и т.д.
Потому каждое значение идентификатора берётся в квадратные скобки (маршрут примет вид наподобие «[1][7][3][6]»), и поиск тоже производится с предварительным заключением искомого идентификатора в квадратные скобки, что гарантирует отсутствие ложных срабатываний.
|
MS SQL |
Решение 7.1.2.b (код процедуры, первый вариант) |
||
|
1 |
|
CREATE PROCEDURE FIND_PATH |
|
|
2 |
|
|
@start_node INT, |
|
3 |
|
|
@finish_node INT |
4AS
5DECLARE @rows_inserted INT = 0;
6
7-- Создание временной таблицы для хранения маршрутов:
8IF OBJECT_ID('tempdb.dbo.#connections_temp', 'U') IS NOT NULL
9DROP TABLE #connections_temp;
10
11CREATE TABLE #connections_temp
12(
13[cn_from] INT,
14[cn_to] INT,
15[cn_cost] DOUBLE PRECISION,
16[cn_bidir] CHAR(1),
17[cn_steps] SMALLINT,
18[cn_route] VARCHAR(1000)
19);
20
21-- Первичное наполнение временной таблицы
22-- существующими маршрутами:
23INSERT INTO #connections_temp
24SELECT [cn_from],
25[cn_to],
26[cn_cost],
27[cn_bidir],
281,
29CONCAT('[', [cn_from], '][', [cn_to], ']')
30 |
|
FROM (SELECT |
[cn_from], |
31 |
|
|
[cn_to], |
32 |
|
|
[cn_cost], |
33 |
|
|
[cn_bidir] |
34 |
|
FROM |
[connections] |
35UNION
36SELECT [cn_to],
37 |
|
|
[cn_from], |
38 |
|
|
[cn_cost], |
39 |
|
|
[cn_bidir] |
40 |
|
FROM |
[connections] |
41WHERE [cn_bidir] = 'Y'
42) AS [connections_bidir];
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 502/545
Пример 47: формирование и анализ связанных структур
MS SQL Решение 7.1.2.b (код процедуры, первый вариант) (продолжение)
43-- Наполнение временной таблицы производными
44-- маршрутами:
45SET @rows_inserted = @@ROWCOUNT;
46WHILE (@rows_inserted > 0)
47BEGIN
48INSERT INTO #connections_temp
49SELECT [connections_next].[cn_from],
50 |
|
[connections_next].[cn_to], |
51 |
|
[connections_next].[cn_cost], |
52 |
|
[connections_next].[cn_bidir], |
53 |
|
[connections_next].[cn_steps], |
54 |
|
[connections_next].[cn_route] |
55 |
|
FROM (SELECT #connections_temp.[cn_from] AS [cn_from], |
56 |
|
[connections].[cn_to] AS [cn_to], |
57 |
|
(#connections_temp.[cn_cost] + |
58 |
|
[connections].[cn_cost]) AS [cn_cost], |
59 |
|
CASE |
60 |
|
WHEN (#connections_temp.[cn_bidir] = 'Y') |
61 |
|
AND ([connections].[cn_bidir] = 'Y') |
62 |
|
THEN 'Y' |
63 |
|
ELSE 'N' |
64 |
|
END AS [cn_bidir], |
65 |
|
(#connections_temp.[cn_steps] + 1) AS [cn_steps], |
66 |
|
CONCAT(#connections_temp.[cn_route], '[', |
67 |
|
[connections].[cn_to], ']') AS [cn_route] |
|
|
|
68FROM #connections_temp
69JOIN (SELECT [cn_from],
70 |
|
|
[cn_to], |
71 |
|
|
[cn_cost], |
72 |
|
|
[cn_bidir] |
73 |
|
FROM |
[connections] |
74 |
|
|
UNION |
75 |
|
SELECT |
[cn_to], |
76 |
|
|
[cn_from], |
77 |
|
|
[cn_cost], |
78 |
|
|
[cn_bidir] |
79 |
|
FROM |
[connections] |
80 |
|
WHERE |
[cn_bidir] = 'Y' |
81 |
|
) AS [connections] |
|
82 |
|
ON #connections_temp.[cn_to] = [connections].[cn_from] |
|
83 |
|
AND CHARINDEX(CONCAT('[', [connections].[cn_to], ']'), |
|
84 |
|
|
#connections_temp.[cn_route]) = 0 |
|
|
|
|
85) AS [connections_next]
86LEFT JOIN #connections_temp
87 |
|
ON [connections_next].[cn_from] = |
#connections_temp.[cn_from] |
88 |
|
AND [connections_next].[cn_to] |
= #connections_temp.[cn_to] |
89WHERE #connections_temp.[cn_from] IS NULL
90AND #connections_temp.[cn_to] IS NULL;
91
92SET @rows_inserted = @@ROWCOUNT;
93END; -- WHILE
94
95-- Извлечение маршрутов, соответствующих условию поиска:
96SELECT *
97FROM #connections_temp
98WHERE [cn_from] = @start_node
99AND [cn_to] = @finish_node
100ORDER BY [cn_cost] ASC;
101GO
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 503/545
Пример 47: формирование и анализ связанных структур
Для второго варианта решения, как и в случае с MySQL, нам понадобятся вспомогательные таблицы для хранения текущего и финальных путей.
MS SQL Решение 7.1.2.b (подготовка ко второму варианту решения)
1-- Создание таблицы для хранения текущего пути:
2IF OBJECT_ID('tempdb.dbo.#current_path', 'U') IS NOT NULL
3DROP TABLE #current_path;
4CREATE TABLE #current_path
5(
6[cp_id] INT NOT NULL IDENTITY (1, 1),
7[cp_from] INT,
8[cp_to] INT,
9[cp_cost] DOUBLE PRECISION,
10[cp_bidir] CHAR(1)
11);
12
13-- Создание таблицы для хранения готовых путей:
14IF OBJECT_ID('tempdb.dbo.#final_paths', 'U') IS NOT NULL
15DROP TABLE #final_paths;
16CREATE TABLE #final_paths
17(
18[fp_id] DOUBLE PRECISION,
19[fp_from] INT,
20[fp_to] INT,
21[fp_cost] DOUBLE PRECISION,
22[fp_bidir] CHAR(1)
23);
Алгоритм второго варианта решения:
•если текущий путь пуст, отправной точкой является точка старта, иначе отправной точкой является точка прибытия последней связи в пути (строки 3445);
•открыть курсор для выбора всех связей между городами (строки 18-32, 47);
•для всех связей повторять цикл, в котором:
oпроверить, совпадает ли отправная точка рассматриваемой связи с текущей отправной точкой (строки 60-61 и, если нет, перейти к следую-
щей итерации цикла;
oпроверить, не присутствует ли уже рассматриваемая связь в пути (строки 63-67) и не приводит ли переход по этой связи к циклическому
маршруту (строки 70-73) — в случае выполнения любого из этих условий перейти к следующей итерации цикла;
oпроверить (строка 76), не совпала ли конечная точка связи с точкой финиша:
если совпала — мы нашли путь, для которого генерируем уникальный идентификатор (строка 78) и переносим в таблицу для хранения найденных путей (строки 79-90), не забыв добавить в конец саму связь, которую мы только что рассматривали (строки
91-101);
если не совпала — путь ещё не найден, а потому: добавляем рассматриваемую связь к текущему пути (строки 106-114), выполняем рекурсивный вызов (строка 117), после которого убираем из текущего пути последнюю связь (строки 120-121).
По завершении работы в таблице final_paths будут находиться все найденные пути между двумя указанными городами.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 504/545
Пример 47: формирование и анализ связанных структур
|
MS SQL |
Решение 7.1.2.b (код процедуры, второй вариант) |
||
|
1 |
|
CREATE PROCEDURE FIND_PATH |
|
|
2 |
|
|
@start_node INT, |
|
3 |
|
|
@finish_node INT |
4AS
5-- Переменные для извлечения данных из курсора:
6DECLARE @cn_from_value INT = 0;
7DECLARE @cn_to_value INT = 0;
8DECLARE @cn_cost_value DOUBLE PRECISION = 0;
9DECLARE @cn_bidir_value CHAR(1) = '0';
10
11-- Текущая "отправная точка"
12DECLARE @from_node INT = 0;
13
14-- Идентификатор найденного пути
15DECLARE @rand_value DOUBLE PRECISION = 0;
16
17-- Курсор для прохода по связям между городами
18DECLARE nodes_cursor CURSOR LOCAL FAST_FORWARD FOR
19SELECT *
20FROM (SELECT [cn_from],
21 |
|
|
[cn_to], |
22 |
|
|
[cn_cost], |
23 |
|
|
[cn_bidir] |
24 |
|
FROM |
[connections] |
25UNION
26SELECT [cn_to],
27 |
|
|
[cn_from], |
28 |
|
|
[cn_cost], |
29 |
|
|
[cn_bidir] |
30 |
|
FROM |
[connections] |
31WHERE [cn_bidir] = 'Y'
32) AS [connections_bidir];
33
34IF ((SELECT COUNT(1)
35FROM #current_path) = 0)
36-- Если текущий путь пуст, отправной точкой является точка старта
37SET @from_node = @start_node;
38ELSE
39-- Если текущий путь НЕ пуст, отправной точкой
40-- является точка прибытия последней связи в пути
41SET @from_node = (SELECT [cp_to]
42 |
|
FROM |
#current_path |
43 |
|
WHERE |
[cp_id] = (SELECT MAX([cp_id]) |
44 |
|
|
FROM #current_path) |
45 |
|
); |
|
46 |
|
|
|
47 |
|
OPEN nodes_cursor; |
|
48 |
|
|
|
|
|
|
|
49WHILE (1 = 1)
50BEGIN
51FETCH NEXT FROM nodes_cursor INTO @cn_from_value,
52 |
|
@cn_to_value, |
53 |
|
@cn_cost_value, |
54 |
|
@cn_bidir_value; |
|
|
|
55IF (@@FETCH_STATUS != 0)
56BREAK;
57
58-- Отправная точка связи не совпадает с текущей
59-- отправной точкой, пропускаем
60IF (@cn_from_value != @from_node)
61CONTINUE;
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 505/545
Пример 47: формирование и анализ связанных структур
MS SQL Решение 7.1.2.b (код процедуры, второй вариант) (продолжение)
62-- Такая связь уже есть в текущем пути, пропускаем
63IF EXISTS (SELECT 1
64 |
|
FROM #current_path |
||
65 |
|
WHERE |
[cp_from] |
= @cn_from_value |
66 |
|
AND |
[cp_to] = |
@cn_to_value) |
67 |
|
CONTINUE; |
|
|
68 |
|
|
|
|
69-- Такая связь приводит к циклу, пропускаем
70IF EXISTS (SELECT 1
71 |
|
FROM #current_path |
72 |
|
WHERE [cp_from] = @cn_to_value) |
73 |
|
CONTINUE; |
74 |
|
|
75-- Конечная точка связи совпала с точкой финиша, путь найден
76IF (@cn_to_value = @finish_node)
77BEGIN
78SET @rand_value = RAND();
79INSERT INTO #final_paths
80 |
|
|
([fp_id], |
81 |
|
|
[fp_from], |
82 |
|
|
[fp_to], |
83 |
|
|
[fp_cost], |
84 |
|
|
[fp_bidir]) |
85 |
|
SELECT @rand_value, |
|
86 |
|
|
[cp_from], |
87 |
|
|
[cp_to], |
88 |
|
|
[cp_cost], |
89 |
|
|
[cp_bidir] |
90 |
|
FROM |
#current_path; |
91 |
|
INSERT INTO #final_paths |
|
92 |
|
|
([fp_id], |
93 |
|
|
[fp_from], |
94 |
|
|
[fp_to], |
95 |
|
|
[fp_cost], |
96 |
|
|
[fp_bidir]) |
97 |
|
VALUES (@rand_value, |
|
98 |
|
|
@cn_from_value, |
99 |
|
|
@cn_to_value, |
100 |
|
|
@cn_cost_value, |
101 |
|
|
@cn_bidir_value); |
102END
103ELSE
104BEGIN
105-- Добавляем связь в текущий путь
106INSERT INTO #current_path
107 |
|
([cp_from], |
108 |
|
[cp_to], |
109 |
|
[cp_cost], |
110 |
|
[cp_bidir]) |
111 |
|
VALUES (@cn_from_value, |
112 |
|
@cn_to_value, |
113 |
|
@cn_cost_value, |
114 |
|
@cn_bidir_value); |
115 |
|
|
|
|
|
116-- Продолжаем рекурсивно искать следующие связи
117EXEC FIND_PATH @start_node, @finish_node;
118
119-- Удаляем последнюю связь из текущего пути
120DELETE FROM #current_path
121 |
|
WHERE [cp_id] = (SELECT MAX([cp_id]) FROM #current_path); |
122END;
123END;
124CLOSE nodes_cursor;
125DEALLOCATE nodes_cursor;
126GO
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 506/545
Пример 47: формирование и анализ связанных структур
Проверим, как работают полученные решения, выполнив такой код.
MS SQL |
Решение 7.1.2.b (код для проверки работоспособности) |
1-- Для первого варианта решения:
2EXEC FIND_PATH {начальная_точка}, {конечная_точка};
3
4-- Для второго варианта решения:
5TRUNCATE TABLE #current_path;
6TRUNCATE TABLE #final_paths;
7EXEC FIND_PATH {начальная_точка}, {конечная_точка};
8SELECT * FROM #final_paths;
Поведение MS SQL Server оказывается полностью эквивалентным поведе-
нию MySQL.
На представленном в начале данного примера наборе данных для поиска пути из города 1 в город 6 оба решения возвращают одинаковые (хоть и по-разному представленные) результаты.
Результат первого варианта решения:
cn_from |
cn_to |
cn_cost |
cn_bidir |
cn_steps |
|
cn_route |
|||||
1 |
|
6 |
30 |
|
N |
|
3 |
|
|
[1][7][3][6] |
|
1 |
|
6 |
85 |
|
N |
|
3 |
|
|
[1][7][2][6] |
|
|
Результат второго варианта решения: |
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|||
|
fp_id |
|
fp_from |
fp_to |
fp_cost |
|
fp_bidir |
|
|||
0.159113517642648 |
1 |
|
7 |
20 |
|
N |
|
||||
0.159113517642648 |
7 |
|
2 |
15 |
|
Y |
|
||||
0.159113517642648 |
2 |
|
6 |
50 |
|
N |
|
||||
0.716279602109358 |
1 |
|
7 |
20 |
|
N |
|
||||
0.716279602109358 |
7 |
|
3 |
5 |
|
N |
|
||||
0.716279602109358 |
3 |
|
6 |
5 |
|
N |
|
Но если в таблицу connections поместить следующие данные
cn_from |
cn_to |
cn_cost |
cn_bidir |
1 |
3 |
100 |
N |
1 |
5 |
100 |
N |
3 |
5 |
20 |
N |
5 |
3 |
200 |
N |
и поискать путь между городами 1 и 5, результаты будут разными. Результат первого варианта решения:
cn_from |
cn_to |
cn_cost |
cn_bidir |
cn_steps |
|
cn_route |
||||||
1 |
|
5 |
100 |
|
N |
|
1 |
|
|
[1][5] |
|
|
|
Результат второго варианта решения: |
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|||
|
fp_id |
|
|
fp_from |
fp_to |
fp_cost |
|
fp_bidir |
|
|||
0.948062188221448 |
|
1 |
|
3 |
100 |
|
N |
|
||||
0.948062188221448 |
|
3 |
|
5 |
20 |
|
N |
|
||||
0.562740117282937 |
|
1 |
|
5 |
100 |
|
N |
|
Таким образом, как и было сказано выше, в MS SQL Server первый вариант решения тоже не находит альтернативные пути разной длины, в то время как второй вариант справляется с этим.
На этом решение для MS SQL Server завершено.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 507/545
Пример 47: формирование и анализ связанных структур
Переходим к Oracle и реализуем решение, представленное выше для MySQL
иMS SQL Server.
Вотличие от двух других СУБД, Oracle не позволяет скомпилировать хранимую процедуру, внутри которой есть обращение к несуществующим объектам — даже если объекты создаются в этой же процедуре несколькими строками выше. Это ограничение можно обходить через EXECUTE IMMEDIATE и иными изощрёнными способами, но для простоты кода мы вынесем создание временной таблицы, с которой работает хранимая процедура, в отдельный код.
Oracle |
Решение 7.1.2.b (подготовка к первому варианту решения) |
1CREATE GLOBAL TEMPORARY TABLE "connections_temp"
2(
3"cn_from" NUMBER(10),
4"cn_to" NUMBER(10),
5"cn_cost" DOUBLE PRECISION,
6"cn_bidir" CHAR(1),
7"cn_steps" NUMBER(5),
8"cn_route" VARCHAR(1000)
9)
10ON COMMIT PRESERVE ROWS;
Алгоритм первого варианта решения:
•в созданную до компиляции хранимой процедуры временную таблицу переносятся все данные из таблицы connections с учётом двунаправленности некоторых связей (строки 10-28; аналогичный подзапрос, учитывающий двунаправленные связи, используется в строках 55-67 — фактически, он представляет собой ничто иное, как тело представления из решения{492} задачи
7.1.2.a{491});
•выполняется цикл поиска производных маршрутов (строки 32-79), в котором: o условием выхода является отсутствие новых маршрутов (переменная Oracle SQL%ROWCOUNT содержит количество записей, затронутых по-
следней операцией модификации данных);
oидея поиска новых маршрутов строится на том, чтобы к уже найденным маршрутам добавлять следующие шаги (конечная точка найденного маршрута совпадает с отправной точкой связи между городами, что проверяется в условии объединения в строке 68; условие в строках 69-70 исключает порождение циклических маршрутов; условие в строках 75-76 исключает бесконечное повторное дублирующихся маршрутов между двумя любыми городами).
•после того, как все возможные производные маршруты построены, в качестве результата работы хранимой процедуры возвращаются только те маршруты, точки отправки и назначения которых совпадают с переданными в хранимую процедуру параметрами (строки 82-87).
Обратите внимание на то, как формируется и анализируется маршрут, раз-
мещаемый в поле cn_route таблицы connections_temp: в Oracle (как и в MS SQL
Server) нет прямого аналога функции MySQL FIND_IN_SET, а при поиске вхожде-
ния подстроки в строку есть шанс, например, «найти» число 12 в числе 123 и т.д. Потому каждое значение идентификатора берётся в квадратные скобки
(маршрут примет вид наподобие «[1][7][3][6]»), и поиск тоже производится с предварительным заключением искомого идентификатора в квадратные скобки, что гарантирует отсутствие ложных срабатываний.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 508/545
Пример 47: формирование и анализ связанных структур
|
Oracle |
|
Решение 7.1.2.b (код процедуры, первый вариант) |
|
|
1 |
|
CREATE OR REPLACE PROCEDURE FIND_PATH (start_node IN NUMBER, |
|
|
2 |
|
|
finish_node IN NUMBER, |
|
3 |
|
|
final_paths OUT SYS_REFCURSOR) |
4AS
5rows_inserted NUMBER := 0;
6BEGIN
7
8-- Первичное наполнение временной таблицы существующими маршрутами:
9INSERT INTO "connections_temp"
10SELECT "cn_from",
11"cn_to",
12"cn_cost",
13"cn_bidir",
141,
15('[' || "cn_from" || '][' || "cn_to" || ']')
16 |
|
FROM (SELECT |
"cn_from", |
17 |
|
|
"cn_to", |
18 |
|
|
"cn_cost", |
19 |
|
|
"cn_bidir" |
20 |
|
FROM |
"connections" |
21UNION
22SELECT "cn_to",
23 |
|
|
"cn_from", |
24 |
|
|
"cn_cost", |
25 |
|
|
"cn_bidir" |
26 |
|
FROM |
"connections" |
27WHERE "cn_bidir" = 'Y'
28) "connections_bidir";
29
30-- Наполнение временной таблицы производными маршрутами:
31rows_inserted := SQL%ROWCOUNT;
32WHILE (rows_inserted > 0)
33LOOP
34INSERT INTO "connections_temp"
35SELECT "connections_next"."cn_from",
36 |
|
"connections_next"."cn_to", |
37 |
|
"connections_next"."cn_cost", |
38 |
|
"connections_next"."cn_bidir", |
39 |
|
"connections_next"."cn_steps", |
40 |
|
"connections_next"."cn_route" |
41 |
|
FROM (SELECT "connections_temp"."cn_from" AS "cn_from", |
42 |
|
"connections"."cn_to" AS "cn_to", |
43 |
|
("connections_temp"."cn_cost" + |
44 |
|
"connections"."cn_cost") AS "cn_cost", |
45 |
|
CASE |
46 |
|
WHEN ("connections_temp"."cn_bidir" = 'Y') |
47 |
|
AND ("connections"."cn_bidir" = 'Y') |
48 |
|
THEN 'Y' |
49 |
|
ELSE 'N' |
50 |
|
END AS "cn_bidir", |
51 |
|
("connections_temp"."cn_steps" + 1) AS "cn_steps", |
52 |
|
("connections_temp"."cn_route" || '[' || |
53 |
|
"connections"."cn_to" || ']') AS "cn_route" |
54 |
|
FROM "connections_temp" |
|
|
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 509/545