I am trying to select the id
of a country
from the countries
table. If the country doesn't exist, I want to insert that country then get the id
of that country. I want to do this a stored function/procedure.
CREATE TABLE countries (
id int
PRIMARY KEY
AUTO_INCREMENT,
country char(2)
NOT NULL,
CONSTRAINT uq_countries_country UNIQUE (country)
);
My attempt at the procedure, but I am clueless as to where I am going wrong. Essentially I am giving a 2 character string, and I should get an id
back from the procedure.
DELIMITER $$
CREATE PROCEDURE GetIPCountryId(
IN _country char(2),
OUT _id int
)
BEGIN
DECLARE _country_id int;
SELECT
id INTO _country_id
FROM countries
WHERE lower(country) = lower(_country)
IF _country_id IS NULL THEN
INSERT INTO countries (country) VALUES (lower(_country));
END IF;
SELECT
id
FROM countries
WHERE lower(country) = lower(_country)
END$$
DELIMITER ;
Use into
in last select.
SELECT
id into _id
FROM countries
WHERE lower(country) = lower(_country)
Also, you can use insert into table select... where not exists..
instead of count and insert
logic.
As far as i know, you can use these 2 methods
NOT EXISTS
INSERT INTO countries(country)
SELECT * FROM countries c
WHERE NOT EXISTS
(SELECT 1 FROM countries c1 WHERE c1.id = c.id)
use ON DUPLICATE KEY UPDATE
SELECT * FROM countries UNION INSERT INTO countries(country) SELECT country FROM countries ON DUPLICATE KEY UPDATE id = values(id)
BOTH of these queries will insert the country into the table if the country doesnt appear on table countries
You would often use LAST_INSERT_ID()
for the purpose of getting the id from an INSERT
:
CREATE PROCEDURE GetIPCountryId (
IN _country char(2),
OUT _id int
)
BEGIN
DECLARE _country_id int;
SELECT
id INTO _country_id
FROM countries
WHERE lower(country) = lower(_country);
IF _country_id IS NULL THEN
INSERT INTO countries (country) VALUES (lower(_country));
SET _id = LAST_INSERT_ID();
END IF;
END$$
Your code fails because the last SELECT
has no INTO
.
However, this is still not the recommended way to handle this logic, because it is subject to race conditions (two users attempting the same insert at the same time). It is better to attempt the insert and then just fetch the value:
CREATE PROCEDURE GetIPCountryId (
IN _country char(2),
OUT _id int
)
BEGIN
INSERT INTO countries (country)
VALUES (lower(_country))
ON DUPLICATE KEY UPDATE country = VALUES(country);
SELECT c.id INTO _id
FROM countries c
WHERE c.country = lower(_country);
END$$
For this to work, you need a unique index or constraint on countries(country)
.
Note: Newer versions of MySQL would use an ON CONFLICT
clause instead of ON DUPLICATE KEY
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.