Advertisement
Guest User

Untitled

a guest
Apr 26th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.50 KB | None | 0 0
  1. CREATE PROCEDURE WITH_EMULATOR(
  2. recursive_table TEXT, # имя рекурсивной таблицы
  3. initial_SELECT TEXT, # источник рекурсии
  4. recursive_SELECT TEXT, # элемент рекурсии
  5. final_SELECT TEXT, # финальный SELECT, выполняющийся над объединенным результатом
  6. max_recursion int unsigned, # защита от бесконечного цикла, используйте 0 по умолчанию
  7. create_table_options TEXT # тут можно задать опции, которые будут использоваться в
  8. # операторе CREATE TABLE при создании рекурсивной таблицы с целью ускорения
  9. # запросов (initial_SELECT/recursive_SELECT/final_SELECT; например:
  10. # "(KEY(some_column)) ENGINE=MEMORY"
  11. )
  12.  
  13. BEGIN
  14. declare new_rows int unsigned;
  15. declare show_progress int default 0; # установите 1 при отладке выполнения
  16. declare recursive_table_next varchar(120);
  17. declare recursive_table_union varchar(120);
  18. declare recursive_table_tmp varchar(120);
  19. set recursive_table_next = concat(recursive_table, "_next");
  20. set recursive_table_union = concat(recursive_table, "_union");
  21. set recursive_table_tmp = concat(recursive_table, "_tmp");
  22.  
  23. # Удаление всех временных таблиц с именами, которые будут использоваться в этой процедуре
  24. SET @str =
  25. CONCAT("DROP TEMPORARY TABLE IF EXISTS ", recursive_table, ",",
  26. recursive_table_next, ",", recursive_table_union,
  27. ",", recursive_table_tmp);
  28. PREPARE stmt FROM @str;
  29. EXECUTE stmt;
  30.  
  31. # Если нужно ссылаться на recursive_table более
  32. # одного раза в recursive_SELECT, удалите ключевое слово TEMPORARY .
  33. SET @str = # создание и заполнение T0
  34. CONCAT("CREATE TEMPORARY TABLE ", recursive_table, " ",
  35. create_table_options, " AS ", initial_SELECT);
  36. PREPARE stmt FROM @str;
  37. EXECUTE stmt;
  38. SET @str = # создание U
  39. CONCAT("CREATE TEMPORARY TABLE ", recursive_table_union, " LIKE ", recursive_table);
  40. PREPARE stmt FROM @str;
  41. EXECUTE stmt;
  42. SET @str = # создание T1
  43. CONCAT("CREATE TEMPORARY TABLE ", recursive_table_next, " LIKE ", recursive_table);
  44. PREPARE stmt FROM @str;
  45. EXECUTE stmt;
  46. if max_recursion = 0 then
  47. set max_recursion = 100; # по умолчанию для предотвращения бесконечного цикла
  48. end if;
  49. recursion: repeat
  50. # добавляем строки из T0 в U (всегда с помощью UNION ALL)
  51. SET @str =
  52. CONCAT("INSERT INTO ", recursive_table_union, " SELECT * FROM ", recursive_table);
  53. PREPARE stmt FROM @str;
  54. EXECUTE stmt;
  55. # цикл будет прерван как только счетчик max_recursion уменьшится до 0
  56. set max_recursion = max_recursion - 1;
  57. if not max_recursion then
  58. if show_progress then
  59. select concat("max recursion exceeded"); # вероятно select "max recursion exceeded";
  60. end if;
  61. leave recursion;
  62. end if;
  63. # выполняем recursive_SELECT на основе T0 и помещаем результат в Т1
  64. SET @str =
  65. CONCAT("INSERT INTO ", recursive_table_next, " ", recursive_SELECT);
  66. PREPARE stmt FROM @str;
  67. EXECUTE stmt;
  68. # прерываем цикл, если в T1 нет строк
  69. select row_count() into new_rows;
  70. if show_progress then
  71. select concat(new_rows, " new rows found");
  72. end if;
  73. if not new_rows then
  74. leave recursion;
  75. end if;
  76. # Подготовка к следующей итерации:
  77. # T1 становится T0, чтобы стать источником получения новых строк при выполнении recursive_SELECT,
  78. # T0 становится T1.
  79. SET @str =
  80. CONCAT("ALTER TABLE ", recursive_table, " RENAME ", recursive_table_tmp);
  81. PREPARE stmt FROM @str;
  82. EXECUTE stmt;
  83. # используется ALTER TABLE RENAME, так как RENAME TABLE не поддерживает временные таблицы
  84. SET @str =
  85. CONCAT("ALTER TABLE ", recursive_table_next, " RENAME ", recursive_table);
  86. PREPARE stmt FROM @str;
  87. EXECUTE stmt;
  88. SET @str =
  89. CONCAT("ALTER TABLE ", recursive_table_tmp, " RENAME ", recursive_table_next);
  90. PREPARE stmt FROM @str;
  91. EXECUTE stmt;
  92. # очищается T1
  93. SET @str =
  94. CONCAT("TRUNCATE TABLE ", recursive_table_next);
  95. PREPARE stmt FROM @str;
  96. EXECUTE stmt;
  97. until 0 end repeat;
  98. # удаляются T0 и T1
  99. SET @str =
  100. CONCAT("DROP TEMPORARY TABLE ", recursive_table_next, ", ", recursive_table);
  101. PREPARE stmt FROM @str;
  102. EXECUTE stmt;
  103. # Объединению промежуточных результатов присваивается имя recursive_table
  104. SET @str =
  105. CONCAT("ALTER TABLE ", recursive_table_union, " RENAME ", recursive_table);
  106. PREPARE stmt FROM @str;
  107. EXECUTE stmt;
  108. # Выполнение окончательного запроса
  109. SET @str = final_SELECT;
  110. PREPARE stmt FROM @str;
  111. EXECUTE stmt;
  112. # Удаление ненужных временных таблиц:
  113. SET @str =
  114. CONCAT("DROP TEMPORARY TABLE ", recursive_table);
  115. PREPARE stmt FROM @str;
  116. EXECUTE stmt;
  117. # Мы сделали это :-)
  118. END;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement