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

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

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

 

Oracle

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

 

55

 

 

JOIN (SELECT

"cn_from",

 

56

 

 

 

"cn_to",

 

57

 

 

 

"cn_cost",

 

58

 

 

 

"cn_bidir"

 

59

 

 

FROM

"connections"

 

60

 

 

 

UNION

 

61

 

 

SELECT

"cn_to",

 

62

 

 

 

"cn_from",

 

63

 

 

 

"cn_cost",

 

64

 

 

 

"cn_bidir"

 

65

 

 

FROM

"connections"

 

66

 

 

WHERE

"cn_bidir" = 'Y'

 

67

 

 

) "connections"

 

68

 

 

ON "connections_temp"."cn_to" = "connections"."cn_from"

 

69

 

 

AND INSTR("connections_temp"."cn_route",

 

70

 

 

 

'[' || "connections"."cn_to" || ']') = 0

71) "connections_next"

72LEFT JOIN "connections_temp"

73

 

ON "connections_next"."cn_from" =

"connections_temp"."cn_from"

74

 

AND "connections_next"."cn_to"

= "connections_temp"."cn_to"

75WHERE "connections_temp"."cn_from" IS NULL

76AND "connections_temp"."cn_to" IS NULL;

77

78rows_inserted := SQL%ROWCOUNT;

79END LOOP;

80

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

82OPEN final_paths FOR

83SELECT *

84FROM "connections_temp"

85WHERE "cn_from" = start_node

86AND "cn_to" = finish_node

87ORDER BY "cn_cost" ASC;

88END;

Для второго варианта решения, как и в случае с MySQL и MS SQL Server, нам понадобятся вспомогательные таблицы для хранения текущего и финальных путей.

Oracle

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

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

2CREATE GLOBAL TEMPORARY TABLE "current_path"

3(

4"cp_id" NUMBER(10),

5"cp_from" NUMBER(10),

6"cp_to" NUMBER(10),

7"cp_cost" NUMBER(15,4),

8"cp_bidir" CHAR(1)

9);

10

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

12CREATE GLOBAL TEMPORARY TABLE "final_paths"

13(

14"fp_id" NUMBER(15,4),

15"fp_from" NUMBER(15,4),

16"fp_to" NUMBER(15,4),

17"fp_cost" NUMBER(15,4),

18"fp_bidir" CHAR(1)

19);

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

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

Алгоритм второго варианта решения:

если текущий путь пуст, отправной точкой является точка старта, иначе отправной точкой является точка прибытия последней связи в пути (строки 2640; обратите внимание на то, как в Oracle проверяется на пустоту результат выполнения запроса — классическое выражение IF (NOT) EXISTS здесь не работает);

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

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

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

oпроверить, не присутствует ли уже рассматриваемая связь в пути (строки 52-60) и не приводит ли переход по этой связи к циклическому маршруту (строки 63-70) — в случае выполнения любого из этих условий перейти к следующей итерации цикла;

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

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

89-99);

если не совпала — путь ещё не найден, а потому: добавляем рассматриваемую связь к текущему пути (строки 102-113), выполняем рекурсивный вызов (строка 116), после которого убираем из текущего пути последнюю связь (строки 119-121).

По завершении работы в таблице final_paths будут находиться все

найденные пути между двумя указанными городами.

 

 

 

Обратите внимание, как в строках 108-109 реализована эмуляция автоинкре-

ментируемого первичного ключа без использования триггера.

 

 

 

 

 

 

 

Oracle

 

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

 

1

 

CREATE OR REPLACE PROCEDURE FIND_PATH (start_node IN NUMBER,

 

 

2

 

 

finish_node IN NUMBER)

 

3AS

4from_node NUMBER(10) := 0;

5rows_count NUMBER(10) := 0;

6rand_value NUMBER(15,4) := 0;

7

8CURSOR nodes_cursor IS

9SELECT "cn_from",

10"cn_to",

11"cn_cost",

12"cn_bidir"

13FROM (SELECT "cn_from",

14

 

"cn_to",

15

 

"cn_cost",

16

 

"cn_bidir"

17

 

FROM "connections"

18UNION

19SELECT "cn_to",

20

 

 

"cn_from",

21

 

 

"cn_cost",

22

 

 

"cn_bidir"

23

 

FROM

"connections"

24

 

WHERE

"cn_bidir" = 'Y');

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

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

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

25BEGIN

26SELECT COUNT(1) INTO rows_count

27FROM "current_path";

28

29IF (rows_count = 0)

30THEN

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

32from_node := start_node;

33ELSE

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

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

36SELECT "cp_to" INTO from_node

37FROM "current_path"

38WHERE "cp_id" = (SELECT MAX("cp_id")

39

 

FROM "current_path");

40

 

END IF;

41

 

 

 

 

 

42FOR one_link IN nodes_cursor

43LOOP

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

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

46IF (one_link."cn_from" != from_node)

47THEN

48CONTINUE;

49END IF;

50

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

52SELECT COUNT(1) INTO rows_count

53FROM (SELECT 1

54FROM "current_path"

55WHERE "cp_from" = one_link."cn_from"

56AND "cp_to" = one_link."cn_to");

57IF (rows_count > 0)

58THEN

59CONTINUE;

60END IF;

61

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

63SELECT COUNT(1) INTO rows_count

64FROM (SELECT 1

65FROM "current_path"

66WHERE "cp_from" = one_link."cn_to");

67IF (rows_count > 0)

68THEN

69CONTINUE;

70END IF;

71

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

73IF (one_link."cn_to" = finish_node)

74THEN

75rand_value := DBMS_RANDOM.VALUE(1,10);

76

 

 

 

77

 

INSERT

INTO "final_paths"

78

 

 

("fp_id",

79

 

 

"fp_from",

80

 

 

"fp_to",

81

 

 

"fp_cost",

82

 

 

"fp_bidir")

83

 

SELECT

rand_value,

84

 

 

"cp_from",

85

 

 

"cp_to",

86

 

 

"cp_cost",

87

 

 

"cp_bidir"

88

 

FROM

"current_path";

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

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

 

Oracle

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

 

89

 

 

INSERT INTO "final_paths"

 

90

 

 

("fp_id",

 

91

 

 

"fp_from",

 

92

 

 

"fp_to",

 

93

 

 

"fp_cost",

 

94

 

 

"fp_bidir")

 

95

 

 

VALUES (rand_value,

 

96

 

 

one_link."cn_from",

 

97

 

 

one_link."cn_to",

 

98

 

 

one_link."cn_cost",

 

99

 

 

one_link."cn_bidir");

 

 

 

 

 

100ELSE

101-- Добавляем связь в текущий путь

102INSERT INTO "current_path"

103

 

("cp_id",

104

 

"cp_from",

105

 

"cp_to",

106

 

"cp_cost",

107

 

"cp_bidir")

108

 

VALUES (NVL((SELECT MAX("cp_id") + 1

109

 

FROM "current_path"), 1),

110

 

one_link."cn_from",

111

 

one_link."cn_to",

112

 

one_link."cn_cost",

113

 

one_link."cn_bidir");

114

 

 

115-- Продолжаем рекурсивно искать следующие связи

116FIND_PATH (start_node, finish_node);

117

118-- Удаляем последнюю связь из текущего пути

119DELETE FROM "current_path"

120WHERE "cp_id" = (SELECT MAX("cp_id")

121

 

FROM "current_path");

122END IF;

123END LOOP;

124END;

Проверим, как работают полученные решения, выполнив представленный ниже код. Поведение Oracle оказывается полностью эквивалентным поведению

MySQL и MS SQL Server.

На представленном в начале данного примера наборе данных для поиска пути из города 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

 

 

4.5847

1

 

7

20

N

 

 

4.5847

7

 

2

15

Y

 

 

4.5847

2

 

6

50

N

 

 

8.5731

1

 

7

20

N

 

 

8.5731

7

 

3

5

 

N

 

 

8.5731

3

 

6

5

 

N

 

 

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

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

Oracle

Решение 7.1.2.b (код для проверки работоспособности)

1-- Для первого варианта решения:

2TRUNCATE TABLE "connections_temp";

3DECLARE

4fp SYS_REFCURSOR;

5cn_from NUMBER(10);

6cn_to NUMBER(10);

7cn_cost DOUBLE PRECISION;

8cn_bidir CHAR(1);

9cn_steps NUMBER(5);

10cn_route VARCHAR(1000);

11BEGIN

12FIND_PATH({начальная_точка}, {конечная_точка}, fp);

13LOOP

14FETCH fp INTO cn_from,

15

 

cn_to,

16

 

cn_cost,

17

 

cn_bidir,

18

 

cn_steps,

19

 

cn_route;

20EXIT WHEN fp%NOTFOUND;

21DBMS_OUTPUT.PUT_LINE(cn_from || ' | ' ||

22

 

cn_to ||

' | '

||

23

 

cn_cost || ' |

' ||

24

 

cn_bidir

|| ' |

' ||

25

 

cn_steps

|| ' |

' ||

26

 

cn_route);

 

27END LOOP;

28CLOSE fp;

29END;

30

31-- Для второго варианта решения:

32TRUNCATE TABLE "current_path";

33TRUNCATE TABLE "final_paths";

34BEGIN

35FIND_PATH({начальная_точка}, {конечная_точка});

36END;

37SELECT * FROM "final_paths";

Но если в таблицу 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

 

 

3.5748

1

 

3

100

N

 

 

3.5748

3

 

5

20

N

 

 

5.881

1

 

5

100

N

 

 

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

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