#mysql #function #stored-procedures #triggers #dynamic-sql
#mysql #функция #хранимые процедуры #триггеры #динамический-sql
Вопрос:
Я пытаюсь обновить таблицу null
значениями. Вот сценарий:
При моем первоначальном запуске таблица выглядела бы следующим образом:
---- ---------- ------- ------- -------
| id | item | col_1 | col_2 | col_3 |
---- ---------- ------- ------- -------
| 1 | abc | 10 | 20 | 30 |
---- ---------- ------- ------- -------
Однако в моих последующих запусках столбцы таблицы будут иметь дополнительные столбцы, которые будут выглядеть следующим образом:
---- ---------- ------- ------- ------- ------- -------
| id | item | col_1 | col_2 | col_3 | col_4 | col_5 |
---- ---------- ------- ------- ------- ------- -------
| 1 | abc | 10 | 20 | 30 | null | null |
---- ---------- ------- ------- ------- ------- -------
| 2 | ghq | null | 40 | null | 50 | 60 | -- triggers the update of row_1. At the same time should update row_2
---- ---------- ------- ------- ------- ------- -------
| 3 | xyz | 70 | 80 | null | 90 | null | -- updates row_3 and same updates moving forward
---- ---------- ------- ------- ------- ------- -------
Вот как это работает в серверной части:
- При первоначальном запуске создается таблица.
- При последующих запусках она изменяет таблицу для добавления дополнительных столбцов (col_4 и col_5).
- Затем обновляет записи, оставляя некоторые пустые ячейки.
Теперь я хочу заполнить пустые ячейки данными, поступающими из другой таблицы.
Я подумываю об использовании триггеров, но, как вы можете видеть выше, обновляемые нули запускаются следующей строкой. С другой стороны, я не совсем уверен, подойдут ли хранимые процедуры и функции.
Я быстро учусь, и мне просто нужны некоторые подсказки или руководства, по крайней мере, о том, какой подход к этому наилучший?
ПОПЫТКА 1: ХРАНИМАЯ ПРОЦЕДУРА ЦИКЛА WHILE
Код ошибки: 1054. Неизвестный столбец ‘@col_name’ в ‘списке полей’
CREATE DEFINER=`admin`@`%` PROCEDURE `fill_null_values`()
BEGIN
DECLARE c INT DEFAULT 0; -- number of columns
DECLARE r INT DEFAULT 0; -- number of rows
DECLARE i INT DEFAULT 0; -- rows counter
DECLARE e INT DEFAULT 0; -- columns counter
DECLARE col_name VARCHAR(100); -- bad table column name
/* initialize c = number of columns */
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'test_db' AND TABLE_NAME = 'bad_table'
INTO c;
/* initialize r = number of rows */
SELECT COUNT(*) FROM bad_table INTO r;
SET i = 0;
SET e = 7; -- starts at column 7
SET col_name = '';
WHILE i <= r DO
WHILE e <= c DO
/* get col_name */
SET col_name = CONCAT("SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'test_db'
AND TABLE_NAME = 'canvass_prices'
AND ORDINAL_POSITION = e");
/* update null values */
SET @sql = CONCAT("UPDATE bad_table
SET `",col_name,"` = (
SELECT ref_data FROM ref_table
JOIN bad_table ON ref_table.id = bad_table.id
WHERE bad_table.ref_data = i)
WHERE `",col_name,"` IS NULL");
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET e = e 1;
END WHILE;
SET i = i 1;
END WHILE;
END
Комментарии:
1. Это кричит о плохом дизайне БД. Если вы, вероятно, получите требуемые новые столбцы, то сделайте так, чтобы база данных записывала столбцы, так сказать, «вниз по странице»
id | Item | ColName | ColValue |
, например. Тогда вы можете изобрести 1000 новыхcol_n
и вам никогда не придется возиться со структурой базы данных2. запускает обновление row_1. В то же время следует обновить row_2 Забудьте — это невозможно. Триггер может изменять только значения в строке, обновление которой вызывает его запуск, и не может влиять на любые другие строки той же таблицы.
3. @RiggsFolly На самом деле это требование, и у меня нет выбора. Я уже выполнил ваше предложение и преобразовал его в столбец, все во время выполнения. Я только что достиг этого момента, пытаясь на этот раз заполнить пустые ячейки.
4. @Akina Спасибо, и я уже могу избежать срабатывания триггера. Я думаю, что единственный вариант, который у меня остался, — это цикл. Что вы думаете?
5. @RickyBelmont 1) Как я вижу, вы допускаете распространенную ошибку — вы думаете, что объявленная
DECLARE col_name VARCHAR(100);
переменная и пользовательская@col_name
переменная — это одно и то же. Я должен сказать вам, что это неправда. 2) Другая ошибка — вы используетеUPDATE bad_table SET @col_name = ...
,INSERT
синтаксис утверждает, что имя столбца должно быть в том месте, где вводится имя пользовательской переменной@col_name
. Это приводит к ошибке. Если вы надеетесь, что переменная будет заменена ее значением — это снова неверно. Вам нужен подготовленный оператор.