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

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

Пример 47: формирование и анализ связанных структур

MySQL

Решение 7.1.2.b (код процедуры, первый вариант) (продолжение)

19-- Первичное наполнение временной таблицы

20-- существующими маршрутами:

21INSERT INTO `connections_temp`

22SELECT `cn_from`,

23`cn_to`,

24`cn_cost`,

25`cn_bidir`,

261,

27CONCAT(`cn_from`, ',', `cn_to`)

28

 

FROM (SELECT

`cn_from`,

29

 

 

`cn_to`,

30

 

 

`cn_cost`,

31

 

 

`cn_bidir`

32

 

FROM

`connections`

 

 

 

 

33UNION DISTINCT

34SELECT `cn_to`,

35

 

 

`cn_from`,

36

 

 

`cn_cost`,

37

 

 

`cn_bidir`

38

 

FROM

`connections`

39WHERE `cn_bidir` = 'Y'

40) AS `connections_bidir`;

41

42-- Наполнение временной таблицы производными

43-- маршрутами:

44SET rows_inserted = ROW_COUNT();

45WHILE (rows_inserted > 0)

46DO

47INSERT INTO `connections_temp`

48SELECT `connections_next`.`cn_from`,

49

 

`connections_next`.`cn_to`,

50

 

`connections_next`.`cn_cost`,

51

 

`connections_next`.`cn_bidir`,

52

 

`connections_next`.`cn_steps`,

53

 

`connections_next`.`cn_route`

54

 

FROM (SELECT `connections_temp`.`cn_from` AS `cn_from`,

55

 

`connections`.`cn_to` AS `cn_to`,

56

 

(`connections_temp`.`cn_cost` +

57

 

`connections`.`cn_cost`) AS `cn_cost`,

58

 

CASE

59

 

WHEN (`connections_temp`.`cn_bidir` = 'Y')

60

 

AND (`connections`.`cn_bidir` = 'Y')

61

 

THEN 'Y'

62

 

ELSE 'N'

63

 

END AS `cn_bidir`,

64

 

(`connections_temp`.`cn_steps` + 1) AS `cn_steps`,

65

 

CONCAT(`connections_temp`.`cn_route`, ',',

66

 

`connections`.`cn_to`) AS `cn_route`

67

 

FROM `connections_temp`

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 495/545

Пример 47: формирование и анализ связанных структур

 

MySQL

Решение 7.1.2.b (код процедуры, первый вариант) (продолжение)

 

68

 

 

JOIN (SELECT

`cn_from`,

 

69

 

 

 

`cn_to`,

 

70

 

 

 

`cn_cost`,

 

71

 

 

 

`cn_bidir`

 

72

 

 

FROM

`connections`

 

73

 

 

 

UNION DISTINCT

 

74

 

 

SELECT

`cn_to`,

 

75

 

 

 

`cn_from`,

 

76

 

 

 

`cn_cost`,

 

77

 

 

 

`cn_bidir`

 

78

 

 

FROM

`connections`

 

79

 

 

WHERE

`cn_bidir` = 'Y'

 

80

 

 

) AS `connections`

 

81

 

 

ON `connections_temp`.`cn_to` = `connections`.`cn_from`

 

82

 

 

AND FIND_IN_SET(`connections`.`cn_to`,

 

83

 

 

 

`connections_temp`.`cn_route`) = 0

84) AS `connections_next`

85LEFT JOIN `connections_temp`

86

 

ON `connections_next`.`cn_from` =

`connections_temp`.`cn_from`

87

 

AND `connections_next`.`cn_to`

= `connections_temp`.`cn_to`

88WHERE `connections_temp`.`cn_from` IS NULL

89AND `connections_temp`.`cn_to` IS NULL;

90

91SET rows_inserted = ROW_COUNT();

92END WHILE;

93-- Извлечение маршрутов, соответствующих условию поиска:

94SELECT *

95FROM `connections_temp`

96WHERE `cn_from` = start_node

97AND `cn_to` = finish_node

98ORDER BY `cn_cost` ASC;

99DROP TABLE IF EXISTS `connections_temp`;

100END;

101$$

102DELIMITER ;

Альтернативное решение, построенное на основе классического алгоритма «поиска вглубь», требует предварительной подготовки: создания в оперативной памяти (ENGINE = MEMORY) двух таблиц и установки максимального уровня вложенности рекурсивных вызовов.

MySQL

Решение 7.1.2.b (подготовка ко второму варианту решения)

1-- Создание таблицы для хранения текущего пути:

2CREATE TABLE IF NOT EXISTS `current_path`

3(

4`cp_id` INT PRIMARY KEY AUTO_INCREMENT,

5`cp_from` INT,

6`cp_to` INT,

7`cp_cost` DOUBLE,

8`cp_bidir` CHAR(1)

9) ENGINE = MEMORY;

10

11-- Создание таблицы для хранения готовых путей:

12CREATE TABLE IF NOT EXISTS `final_paths`

13(

14`fp_id` DOUBLE,

15`fp_from` INT,

16`fp_to` INT,

17`fp_cost` DOUBLE,

18`fp_bidir` CHAR(1)

19) ENGINE = MEMORY;

20

21-- Установка максимального уровня вложенности рекурсивных вызовов:

22SET @@SESSION.max_sp_recursion_depth = 255;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 496/545

Пример 47: формирование и анализ связанных структур

Теперь можно реализовывать алгоритм:

если текущий путь пуст, отправной точкой является точка старта, иначе отправной точкой является точка прибытия последней связи в пути (строки 4054);

открыть курсор для выбора всех связей между городами (строки 18-32, 56);

для всех связей повторять цикл, в котором:

oпроверить, совпадает ли отправная точка рассматриваемой связи с текущей отправной точкой (строки 69-72) и, если нет, перейти к следующей итерации цикла;

oпроверить, не присутствует ли уже рассматриваемая связь в пути (строки 74-80) и не приводит ли переход по этой связи к циклическому

маршруту (строки 83-88) — в случае выполнения любого из этих условий перейти к следующей итерации цикла;

oпроверить (строка 91), не совпала ли конечная точка связи с точкой финиша:

если совпала — мы нашли путь, для которого генерируем уникальный идентификатор (строка 93) и переносим в таблицу для хранения найденных путей (строки 95-118), не забыв добавить в конец саму связь, которую мы только что рассматривали (строки

108-118);

если не совпала — путь ещё не найден, а потому: добавляем рассматриваемую связь к текущему пути (строки 121-131), выполняем рекурсивный вызов (строка 134), после которого убираем из текущего пути последнюю связь (строки 137-140: MySQL не позволяет одновременно читать и удалять данные из таблицы, потому идентификатор последней записи мы помещаем в переменную в строках 137-138, а затем используем в условии в строке 140).

По завершении работы в таблице final_paths будут находиться все найденные пути между двумя указанными городами.

MySQL

Решение 7.1.2.b (код процедуры, второй вариант)

1DELIMITER $$

2CREATE PROCEDURE FIND_PATH (IN start_node INT,

3

 

IN finish_node INT)

4BEGIN

5-- Признак выхода из цикла курсора:

6DECLARE done INT DEFAULT 0;

7

8-- Переменные для извлечения данных из курсора:

9DECLARE cn_from_value INT DEFAULT 0;

10DECLARE cn_to_value INT DEFAULT 0;

11DECLARE cn_cost_value DOUBLE DEFAULT 0;

12DECLARE cn_bidir_value CHAR(1) DEFAULT 0;

13

14-- Текущая "отправная точка"

15-- ВАЖНО! Эту переменную нельзя делать @глобальной !

16DECLARE from_node INT DEFAULT 0;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 497/545

Пример 47: формирование и анализ связанных структур

MySQL

Решение 7.1.2.b (код процедуры, второй вариант) (продолжение)

17-- Курсор

18DECLARE nodes_cursor CURSOR FOR

19SELECT *

20FROM (SELECT `cn_from`,

21

 

 

`cn_to`,

22

 

 

`cn_cost`,

23

 

 

`cn_bidir`

24

 

FROM

`connections`

 

 

 

 

25UNION DISTINCT

26SELECT `cn_to`,

27

 

 

`cn_from`,

28

 

 

`cn_cost`,

29

 

 

`cn_bidir`

30

 

FROM

`connections`

 

 

 

 

31WHERE `cn_bidir` = 'Y')

32AS `connections_bidir`;

33-- здесь можно дописать

34-- WHERE `cn_from` = from_node

35-- и убрать далее

36-- IF (cn_from_value != from_node)

37

38 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 39

40IF ((SELECT COUNT(1)

41FROM `current_path`) = 0)

42THEN

43-- Если текущий путь пуст, отправной точкой

44-- является точка старта

45SET from_node = start_node;

46ELSE

47-- Если текущий путь НЕ пуст, отправной точкой

48-- является точка прибытия последней связи в пути

49SET from_node = (SELECT `cp_to`

50

 

FROM `current_path`

51

 

WHERE `cp_id` = (SELECT MAX(`cp_id`)

52

 

FROM `current_path`)

53

 

);

54

 

END IF;

55

 

 

56

 

OPEN nodes_cursor;

57

 

 

58nodes_loop: LOOP

59FETCH nodes_cursor INTO cn_from_value,

60

 

cn_to_value,

61

 

cn_cost_value,

62

 

cn_bidir_value;

63IF done THEN

64LEAVE nodes_loop;

65END IF;

66

67-- Отправная точка связи не совпадает с текущей

68-- отправной точкой, пропускаем

69IF (cn_from_value != from_node)

70THEN

71ITERATE nodes_loop;

72END IF;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 498/545

Пример 47: формирование и анализ связанных структур

MySQL

Решение 7.1.2.b (код процедуры, второй вариант) (продолжение)

73-- Такая связь уже есть в текущем пути, пропускаем

74IF EXISTS (SELECT 1

75

 

FROM `current_path`

76

 

WHERE

`cp_from`

= cn_from_value

77

 

AND

`cp_to` =

cn_to_value)

 

 

 

 

 

78THEN

79ITERATE nodes_loop;

80END IF;

81

82-- Такая связь приводит к циклу, пропускаем

83IF EXISTS (SELECT 1

84

 

FROM `current_path`

85

 

WHERE `cp_from` = cn_to_value)

86THEN

87ITERATE nodes_loop;

88END IF;

89

90-- Конечная точка связи совпала с точкой финиша, путь найден

91IF (cn_to_value = finish_node)

92THEN

93SET @rand_value = RAND();

94

 

 

95

 

INSERT INTO `final_paths`

96

 

(`fp_id`,

97

 

`fp_from`,

98

 

`fp_to`,

99

 

`fp_cost`,

100

 

`fp_bidir`)

 

 

 

101SELECT @rand_value,

102`cp_from`,

103`cp_to`,

104`cp_cost`,

105`cp_bidir`

106FROM `current_path`;

107

 

 

108

 

INSERT INTO `final_paths`

109

 

(`fp_id`,

110

 

`fp_from`,

111

 

`fp_to`,

112

 

`fp_cost`,

113

 

`fp_bidir`)

114

 

VALUES (@rand_value,

115

 

cn_from_value,

116

 

cn_to_value,

117

 

cn_cost_value,

118

 

cn_bidir_value);

119

 

ELSE

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 499/545

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