Материал: Using_MySql,_MS_SQL_Server_and_Oracle(1)

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Пример 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

Источник: https://studfile.net/preview/16418462/