简体   繁体   English

MYSQL - 在 INSERT 语句中使用函数

[英]MYSQL - using Functions inside a INSERT statement

I am moving data from Spreadsheets to MySQL.我正在将数据从电子表格移动到 MySQL。 So we know that in Spreadsheets usually there is no ID, instead, just text.所以我们知道在电子表格中通常没有 ID,而是只有文本。

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

With that in mind, let's consider two tables:考虑到这一点,让我们考虑两个表:

Country : [ID, name]国家:[身份证,姓名]

City : [ID , country (FK) , name]城市 : [ID , country (FK) , name]

I dont want to create several countries with the same name -- but I want to use the existing one.我不想创建多个同名的国家——但我想使用现有的国家。 Perfect, so, let's add a FUNCTION in the INSERT state that searches, insert (if needed) and return the Country ID.完美,所以,让我们在 INSERT 状态中添加一个 FUNCTION 来搜索、插入(如果需要)并返回国家/地区 ID。

So I created a Function to FIRST assess whether the Country exists if not then create a country所以,我创建了一个功能,首先评估该国是否存在如果没有则创建国家

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

And then I have DOZENS OF THOUSANDS of INSERTS such as然后我有成千上万的插入,例如

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

The Function works well when executed alone, such as该函数单独执行时效果很好,例如

SELECT getCountry('Aruba');

However, when I execute that in that VERY LONG SQL (22K+ rows) then it does not work.... it uses basically the latest ID that was created BEFORE starting the execution.但是,当我在非常长的 SQL(22K+ 行)中执行它时,它不起作用......它基本上使用在开始执行之前创建的最新 ID。 Maybe I should "wait" the function execute and return a proper result?也许我应该“等待”函数执行并返回正确的结果? But How?但是如何?

What am I doing wrong?我究竟做错了什么?

Instead of function why not use a Stored Procedure, then the procedure will process the checking and insertion.为什么不使用存储过程而不是函数,那么过程将处理检查和插入。

https://www.mysqltutorial.org/getting-started-with-mysql-stored-procedures.aspx 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 ;

And if you want to execute a procedure如果你想执行一个程序

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');

You can also add a condition to check if the city and country exists to prevent duplicate entry.您还可以添加条件来检查城市和国家/地区是否存在,以防止重复输入。

I can't find any documentation of it, but maybe there's a conflict when you do an INSERT in a function that's called during another INSERT .我找不到它的任何文档,但是当您在另一个INSERT期间调用的函数中执行INSERT时,可能会发生冲突。 So try splitting them up using a variable:因此,尝试使用变量将它们拆分:

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

Using the idea of @Barman, PLUS adding COMMIT to each row I could solve that:使用@Barman 的想法,加上向每一行添加 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;

Without the COMMIT at the end of each row, MySQL was not calculating the variable anymore, instead, just throwing some last result it collected.如果每行末尾没有 COMMIT,MySQL 就不再计算变量,而是抛出它收集的最后一个结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM