MYSQL - использование функций внутри оператора INSERT - PullRequest
0 голосов
/ 24 марта 2020

Я перемещаю данные из электронных таблиц в MySQL. Итак, мы знаем, что в электронных таблицах обычно нет идентификатора, вместо этого просто текст.

City;Country;...
New York;USA;...
Berlim;Germany;...
Munich,Germany,...

Имея это в виду, давайте рассмотрим две таблицы:

Страна: [ID, имя]

Город: [ID, страна (FK), имя]

Я не хочу создавать несколько стран с одинаковыми именами, но я хочу использовать существующую. Отлично, так что давайте добавим ФУНКЦИЮ в состоянии ВСТАВИТЬ, которая выполняет поиск, вставляет (при необходимости) и возвращает идентификатор страны.

Итак, я создал функцию, чтобы FIRST оценить, существует ли Страна если нет, то создать страну

getCountry (parameter IN strCountry varchar(100))
BEGIN
SELECT ID INTO @id from `country` WHERE country.country = strCountry ;
IF (@id is NULL OR @id= 0) THEN
    INSERT INTO `country` (country) VALUES (strCountry);
    if (ROW_COUNT()>0) THEN
        SET @id = LAST_INSERT_ID();
    else
        SET @id = NULL;
    END IF;
END IF ;
RETURN @id;
END

А потом у меня есть Десятки тысяч вставок, таких как

INSERT INTO city (name, country) VALUES ('name of the city', getCountry('new or existing one'));

Функция хорошо работает при выполнении один, например

SELECT getCountry('Aruba');

Однако, когда я выполняю это в этих ОЧЕНЬ ДЛИННЫХ SQL (22K + строки), он не работает .... он использует в основном последний идентификатор, созданный ДО запуска выполнение. Может быть, я должен «дождаться» выполнения функции и вернуть правильный результат? Но как?

Что я делаю не так?

Ответы [ 3 ]

1 голос
/ 24 марта 2020

Вместо функции, почему бы не использовать хранимую процедуру, тогда процедура обработает проверку и вставку.

https://www.mysqltutorial.org/getting-started-with-mysql-stored-procedures.aspx

DELIMITER $$
CREATE PROCEDURE `sp_city_add`(in p_city varchar(100), in p_country varchar(100))
BEGIN

DECLARE country_id INT;

IF (SELECT COUNT(1) FROM country WHERE country.country = p_country) = 0 THEN
    INSERT INTO country (country) VALUE (p_country);

    SET country_id = LAST_INSERT_ID();
ELSE
    SELECT ID INTO country_id FROM country WHERE country.country = p_country;
END IF;

INSERT INTO city (name, country) VALUES (p_city, country_id);

END$$
DELIMITER ;

И если вы хотите выполнить процедуру

CALL sp_city_add('Bogota', 'Colombia');
CALL sp_city_add('Phnom Penh', 'Cambodia');
CALL sp_city_add('Yaounde', 'Cameroon');
CALL sp_city_add('Ottawa', 'Canada');
CALL sp_city_add('Santiago', 'Chile');
CALL sp_city_add('Beijing', 'China');
CALL sp_city_add('Bogotá', 'Colombia');
CALL sp_city_add('Moroni', 'Comoros');

Вы также можете добавить условие, чтобы проверить, если город и страна существуют для предотвращения дублирования записи.

0 голосов
/ 24 марта 2020

Используя идею @Barman, PLUS добавив COMMIT к каждой строке Я мог бы решить, что:

SELECT @id := getCountry("Colombia");INSERT into city ( city, country) VALUES ('Bogota',@id);COMMIT;
SELECT @id := getCountry("Colombia");INSERT into city ( city, country) VALUES ('Medelin',@id);COMMIT;
SELECT @id := getCountry("Brazil");INSERT into city ( city, country) VALUES ('Medelin',@id);COMMIT;
SELECT @id := getCountry("Brazil");INSERT into city ( city, country) VALUES ('Sao Paulo',@id);COMMIT;
SELECT @id := getCountry("Brazil");INSERT into city ( city, country) VALUES ('Curitiba',@id);COMMIT;
SELECT @id := getCountry("USA");INSERT into city ( city, country) VALUES ('Boston',@id);COMMIT;
SELECT @id := getCountry("USA");INSERT into city ( city, country) VALUES ('DallaS',@id);COMMIT;

Без COMMIT в конце каждой строки, MySQL было больше не вычислять переменную, а просто выбросить последний полученный результат.

0 голосов
/ 24 марта 2020

Я не могу найти какую-либо документацию об этом, но, возможно, возникает конфликт, когда вы делаете INSERT в функции, которая вызывается во время другой INSERT. Поэтому попробуйте разделить их, используя переменную:

SELECT @country := getCountry('new or existing one');
INSERT INTO city (name, country) VALUES ('name of the city', @country);
...